Closed aegershman closed 5 years ago
@aegershman Not ungrateful :) Valid feedback based on the user experience of how this is currently designed. Let me think about how we can update using the feedback above. Stay tuned....
@aegershman
Here's the format that I am planning to more forward with in cf-mgmt.yml config file.
service-access:
- service: p.mysql # would enable for the org listed as well as any protected org
plan: db-medium
orgs:
- cfdev-org
- service: p.mysql # would disable for access for this plan for all orgs
plan: db-large
disable: true
- service: p.rabbitmq # would enable for all plans for all orgs (aka public)
- service: p.redis # would enable for all plans for only cfdev-org and all protected orgs
orgs:
- cfdev-org
- service: p.random # would disable for access for all plans for all orgs
disable: true
Unless I'm missing something I believe with this format I can accomplish all of the scenarios above.
Let me know if you have any questions. Will be working through how to migrate the current format of service-access away from in each org.yml file.
Right on, will get some coworker feedback + will think more on this later today & next few days 👍
I converted some of our existing service-access config over to the proposed syntax and came away with feedback. I have a bit more after this, will include in later comment.
also, goes w/o saying, but I'm not trying to commandeer the use-case or be naggy, fully respect the decision on direct you take, etc., so with that said here's some takeaways I have:
as per cf enable-service-access -h
, there may be a situation where the service name is ambiguous which requires the broker to be specified
cf enable-service-access SERVICE [-b BROKER] [-p PLAN] [-o ORG]
-b Enable access to a service from a particular service broker. Required when service name is ambiguous
presumably this could be solved by making the broker an optional field
- service: "p.mysql-v2"
broker: dedicated-mysql-broker
plan: "db-small-single-node"
orgs:
- myorg1
- myorg2
orgs: []
ambiguityWhat happens if I specify an empty array of orgs? Does it disable access to all orgs and then enables it for all the protected
orgs? That's actually a pretty decent option, in my opinion. If specifying orgs: [x,y]
will enable a service for the orgs x
and y
and all the protected
orgs, then specifying an empty orgs
array should only make the service/plan available to everything in protected
.
- service: "p.mysql-v2"
plan: "db-small-single-node"
orgs: []
Which I assume is different from the following situation, which will disable (... I assume?) access to all orgs including the protected
orgs
- service: "p.mysql-v2"
plan: "db-small-single-node"
disabled: true
disabled
ambiguityThis situation could be a bit confusing. I assume that if disabled: true
then params like orgs:
would be ignored. I don't know if there's a way to either warn/fail on this config case or ensure that the cf-mgmt-config
command will remove the entire orgs
key when setting the service to disable
... Or if nothing will happen at all and it's up to users to maintain their config properly. I don't know, but I can definitely see this happening:
- service: db-small-single-node
disabled: true
orgs:
- myorg1
- myorg2
Something looking at that might think "is it disabled only for those orgs? Is it enabled for all others?", etc., when in reality it's disabled for all orgs and the orgs:
block is irrelevant. I guess the question is "should this warn or fail or flat-out ignore orgs
and keep chugging along?"
If a broker/service/plan/org isn't found registered against the cf
foundation, should the job fail immediately? My view is "probably, yeah", because it helps avoid both mistakenly thinking something was properly configured and prevents config drift, wherein config for brokers/services/plans/org are left around and never cleaned up even if they don't exist against the cf
foundation anymore
Does ordering matter? Let's say I have 7 different plans for some reason. I want all of them to be enabled EXCEPT for two of the plans. One of those plans, db-very-expensive
, should be disabled to everyone (why is it still around? No idea. Work with me here.) The other of those plans, db-small-single-node
, should only be available to two orgs. Now we're in a situation where either:
db-very-expensive
, and make plan db-small-single-node
only available to [these-orgs]". That would look like this:# enable service and all it's plans to everyone...
- service: "p.mysql-v2"
# ... EXCEPT db-very-expensive, which is deactivated...
- service: "p.mysql-v2"
plan: "db-very-expensive"
disabled: true
# ... AND EXCEPT db-small-single-node, which is only available to these two orgs:
- service: "p.mysql-v2"
plan: "db-small-single-node"
orgs:
- myorg1
- myorg2
If this is unordered/parallel, there's a race condition; if enabling the service and all it's plans triggers after the other two, it renders them useless.
Regardless of whether doing this is a good idea or not it should probably be documented whether this is considered to operate in order/parallel?
As a sidenote, a more explicit albeit verbose solution is to explicitly define all other plans of the service as "enabled":
# example of explicitly declaring all plans of a service as enabled. Any plans NOT declared in this config are considered "indeterminate"
- service: "p.mysql-v2"
plan: db-small
- service: "p.mysql-v2"
plan: db-medium
- service: "p.mysql-v2"
plan: db-large
- service: "p.mysql-v2"
plan: db-pretty-large-but-not-too-large
- service: "p.mysql-v2"
plan: db-galera-small
- service: "p.mysql-v2"
plan: db-galera-medium
- service: "p.mysql-v2"
plan: db-galera-large
- service: "p.mysql-v2"
plan: db-very-expensive
disabled: true
- service: "p.mysql-v2"
plan: db-small-single-node
orgs:
- myorg1
- myorg2
(a few more thoughts on the way, am writing them up--)
I think it's worth reassessing the structure of the access
config schema.
Having many individual entries will get cluttered. For example, here's the result of cf service-access
for a "sandbox" foundation.
broker: app-autoscaler
service plan access orgs
app-autoscaler standard all
broker: aws-services-broker
service plan access orgs
aws-dynamodb standard limited myorg1
aws-rds-aurora basic limited myorg1
aws-rds-aurora enterprise limited myorg1
aws-rds-aurora premium limited myorg1
aws-rds-aurora standard limited myorg1
aws-rds-mariadb basic limited myorg1
aws-rds-mariadb enterprise limited myorg1
aws-rds-mariadb premium limited myorg1
aws-rds-mariadb standard limited myorg1
aws-rds-mysql basic limited myorg1
aws-rds-mysql enterprise limited myorg1
aws-rds-mysql premium limited myorg1
aws-rds-mysql standard limited myorg1
aws-rds-oracle basic limited myorg1
aws-rds-oracle enterprise limited myorg1
aws-rds-oracle premium limited myorg1
aws-rds-oracle standard limited myorg1
aws-rds-postgres basic limited myorg1
aws-rds-postgres enterprise limited myorg1
aws-rds-postgres premium limited myorg1
aws-rds-postgres standard limited myorg1
aws-rds-sqlserver basic limited myorg1
aws-rds-sqlserver enterprise limited myorg1
aws-rds-sqlserver premium limited myorg1
aws-rds-sqlserver standard limited myorg1
aws-s3 standard limited myorg1
aws-sqs standard limited myorg1
broker: dedicated-mysql-broker
service plan access orgs
p.mysql db-large all
p.mysql db-medium all
p.mysql db-small all
p.mysql db-xlarge all
p.mysql leader-follower all
broker: identity-service-broker
service plan access orgs
p-identity aeg-dev limited myorg2
p-identity uaa limited myorg1
broker: metrics-forwarder
service plan access orgs
metrics-forwarder unlimited all
broker: newrelic-broker
service plan access orgs
newrelic xyz-sandbox none
broker: nfsbroker
service plan access orgs
nfs-legacy Existing limited system,yugabyte_service_broker-org
nfs Existing limited system,yugabyte_service_broker-org
broker: p-rabbitmq
service plan access orgs
p-rabbitmq standard limited p-spring-cloud-services,system
broker: p-redis
service plan access orgs
p-redis shared-vm none
broker: p-spring-cloud-services
service plan access orgs
p-circuit-breaker-dashboard standard limited myorg2,system
p-config-server standard all
p-service-registry standard all
broker: rabbitmq-odb
service plan access orgs
p.rabbitmq clustered-3.7 all
p.rabbitmq single-node-3.7 all
broker: redis-odb
service plan access orgs
p.redis cache-medium all
p.redis cache-small all
broker: scheduler-for-pcf
service plan access orgs
scheduler-for-pcf standard all
broker: yugabyte_service_broker
service plan access orgs
yugabyte-db large limited myorg1
yugabyte-db medium limited myorg1
yugabyte-db small limited myorg1
yugabyte-db x-large limited myorg1
yugabyte-db x-small limited myorg1
As you can see there are a lot of plans and services. Let's hone in on the the aws-service-broker
(in other foundations we have the azure-broker
, which has just as many plans/services. This list will only continue to grow... super cool)
In order to make all the aws
-related plans available to myorg1
, and assuming we aren't configuring enabling/disabling specific plans like aws-rds-aurora/basic
vs. aws-rds-aurora/enterprise
, etc. the minimum config would be this:
access:
- service: aws-dynamodb
orgs:
- myorg1
- service: aws-rds-aurora
orgs:
- myorg1
- service: aws-rds-mariadb
orgs:
- myorg1
- service: aws-rds-mysql
orgs:
- myorg1
- service: aws-rds-oracle
orgs:
- myorg1
- service: aws-rds-postgres
orgs:
- myorg1
- service: azure-servicebus
orgs:
- myorg1
- service: aws-rds-sqlserver
orgs:
- myorg1
- service: aws-s3
orgs:
- myorg1
- service: aws-sqs
orgs:
- myorg1
And again, when we need to explicitly declare plans
, that's more entries:
access:
- service: aws-dynamodb
orgs:
- myorg1
# aws-rds-aurora
- service: aws-rds-aurora
plan: basic
orgs:
- myorg1
- service: aws-rds-aurora
plan: enterprise
orgs:
- myorg1
- service: aws-rds-aurora
plan: premium
disabled: true
- service: aws-rds-aurora
plan: standard
orgs:
- myorg1
# aws-rds-mariadb
- service: aws-rds-mariadb
plan: basic
orgs:
- myorg1
- service: aws-rds-mariadb
plan: enterprise
orgs:
- myorg1
- service: aws-rds-mariadb
plan: premium
disabled: true
- service: aws-rds-mariadb
plan: standard
orgs:
- myorg1
# aws-rds-mysql
- service: aws-rds-mysql
plan: basic
orgs:
- myorg1
- service: aws-rds-mysql
plan: enterprise
orgs:
- myorg1
- service: aws-rds-mysql
plan: premium
disabled: true
- service: aws-rds-mysql
plan: standard
orgs:
- myorg1
# aws-rds-oracle
- service: aws-rds-oracle
plan: basic
orgs:
- myorg1
- service: aws-rds-oracle
plan: enterprise
orgs:
- myorg1
- service: aws-rds-oracle
plan: premium
disabled: true
- service: aws-rds-oracle
plan: standard
orgs:
- myorg1
# aws-rds-postgres
- service: aws-rds-postgres
plan: basic
orgs:
- myorg1
- service: aws-rds-postgres
plan: enterprise
orgs:
- myorg1
- service: aws-rds-postgres
plan: premium
disabled: true
- service: aws-rds-postgres
plan: standard
orgs:
- myorg1
# aws-rds-sqlserver
- service: aws-rds-sqlserver
plan: basic
orgs:
- myorg1
- service: aws-rds-sqlserver
plan: enterprise
orgs:
- myorg1
- service: aws-rds-sqlserver
plan: premium
disabled: true
- service: aws-rds-sqlserver
plan: standard
orgs:
- myorg1
- service: aws-s3
orgs:
- myorg1
- service: aws-sqs
orgs:
- myorg1
This is demoing the config for only this one broker. This is pretty intense, in my opinion.
In a comment below I'm about going to workshop out some ideas, so bare with me. Unclear if this is the best model, how feasible it is to implement, not trying to impose, etc. Just sharing.
(more thoughts on the way, am writing them up again--)
last one:
Is there benefit to consolidating the model to have plans:
be a list on the service
struct?
using the aws-broker
example:
access:
- service: aws-dynamodb
orgs:
- myorg1
# aws-rds-aurora
- service: aws-rds-aurora
plans:
- plan: basic
orgs:
- myorg1
- plan: enterprise
orgs:
- myorg1
- plan: premium
disabled: true
- plan: standard
orgs:
- myorg1
# aws-rds-mariadb
- service: aws-rds-mariadb
plans:
- plan: basic
orgs:
- myorg1
- plan: enterprise
orgs:
- myorg1
- plan: premium
disabled: true
- plan: standard
orgs:
- myorg1
# aws-rds-mysql
- service: aws-rds-mysql
plans:
- plan: basic
orgs:
- myorg1
- plan: enterprise
orgs:
- myorg1
- plan: premium
disabled: true
- plan: standard
orgs:
- myorg1
# aws-rds-oracle
- service: aws-rds-oracle
plans:
- plan: basic
orgs:
- myorg1
- plan: enterprise
orgs:
- myorg1
- plan: premium
disabled: true
- plan: standard
orgs:
- myorg1
# aws-rds-postgres
- service: aws-rds-postgres
plans:
- plan: basic
orgs:
- myorg1
- plan: enterprise
orgs:
- myorg1
- plan: premium
disabled: true
- plan: standard
orgs:
- myorg1
# aws-rds-sqlserver
- service: aws-rds-sqlserver
plans:
- plan: basic
orgs:
- myorg1
- plan: enterprise
orgs:
- myorg1
- plan: premium
disabled: true
- plan: standard
orgs:
- myorg1
- service: aws-s3
orgs:
- myorg1
- service: aws-sqs
orgs:
- myorg1
So not perfect, but we do have fewer lines of code && fewer top-level keys in the access:
list. It makes it easier to organize and reduces visual clutter. Purely speculative but I imagine this could benefit the cf-mgmt-config global service-access
logic/UX too? This way all the plans
for a service
are under a single service
object, so you don't need to look up every service:
key name of every entry in the access
list? ... Again, idk, just spitballing.
As was said in a comment above, if you want to do something like "enable ALL plans of a service to everyone, EXCEPT for a few select limiting rules-- for example, "make all mysql plans available to everyone, EXCEPT only make db-really-expensive
available to one org" or something-- it's contingent on these service-access rules being ordered and sequential.
Assuming the above structure, what if there were a key for something like enable-all-first
?
That way, instead of this:
- service: "p.mysql-v2"
plans:
- plan: db-small
- plan: db-medium
- plan: db-large
- plan: db-pretty-large-but-not-too-large
- plan: db-galera-small
- plan: db-galera-medium
- plan: db-galera-large
- plan: db-very-expensive
disabled: true
- plan: db-small-single-node
orgs:
- myorg1
- myorg2
You could do this:
# I'm going to come back to this example down below
- service: "p.mysql-v2"
enable-all-first: true
plans:
- plan: db-very-expensive
disabled: true
- plan: db-small-single-node
orgs:
- myorg1
- myorg2
broker
?As we know from cf service-access
we can see the UX organizes by BROKER, then by SERVICE, then by SERVICE PLAN. What if we follow that model in the config, too?
access:
- broker: aws-services-broker # "broker" as top level key; prevents the requirement of repeating `broker` as part of each `service` model
services:
- service: aws-dynamodb
orgs:
- myorg1
- service: aws-rds-aurora
plans:
- plan: basic
orgs:
- myorg1
- plan: enterprise
orgs:
- myorg1
- plan: premium
disabled: true
- plan: standard
orgs:
- myorg1
- service: aws-rds-mariadb
plans:
- plan: basic
orgs:
- myorg1
- plan: enterprise
orgs:
- myorg1
- plan: premium
disabled: true
- plan: standard
orgs:
- myorg1
broker:
as top-level key might naturally replace idea of "enable-all-first"?Assuming these lists are ordered and sequential, then model has the benefit of naturally featuring the idea of enable-all-first
, because you can specify the service
such that it'd have all plans available to everyone. For example:
Instead of this, which requires enable-all-first
to have all the service's plans be made available to everyone and THEN have specific plans be limited/controlled...
- service: "p.mysql-v2"
enable-all-first: true
plans:
- plan: db-very-expensive
disabled: true
- plan: db-small-single-node
orgs:
- myorg1
- myorg2
... you, hypothetically, could do this:
- broker: p.mysql
services:
- service: "p.mysql" # enables ALL plans of service "p.mysql" to all orgs
- service: "p.mysql" # followed immediately by config which enforces limits on each plan
plans:
- plan: db-very-expensive
disabled: true
- plan: db-small-single-node
orgs:
- myorg1
- myorg2
this could also be used to disable all services/plans first, then selectively enable a plan to certain orgs?
- broker: p.mysql
services:
- service: "p.mysql"
disabled: true
- service: "p.mysql"
plans:
- plan: db-small-single-node
orgs:
- myorg1
- myorg2
If specifying multiples of the same service: xyz
is problematic, then EITHER something like enable-all-first: true
(again, not sure if that's a good idea or not) could be specified, OR the expectation just be that admins explicitly declare all the plans
for a given service
in order to enable/disable them. It adds more lines of code, but if it means a cleaner programming model / conceptual model, then boo hoo, the added lines of code are definitely clearly worth it.
Does all of this add too much complexity?
What would the CLI UX look like?! Would it be attrocious?
How are brokers, services, plans, etc. added and removed via the CLI?
Should service-access
the job blow right the hell up (exit 1
) if a broker/service/plan/org defined in config doesn't exist on the foundation? (If this is put to a vote, my opinion is "yes" in order to prevent mistakes, config drift, etc.)
If broker
is used as top-level key, downside is the broker name is less commonly known? Easy solution though, which is just look it up from cf-cli using cf service-access
, it'll spit it right out.
Want to emphasize that many of these ideas (especially enable-all-first
? which the more I think about I don't like the naming of it?) are shaky and could use feedback/incubation.
Anyway that's pretty much all the feedback I've got for the moment. Please don't feel compelled to rush (let alone implement?) this unless you're totally jazzed about the conceptual model. I feel like service-access
is one of the more complicated configuration setups.
Disclaimer because I feel guilty about asking without directly contributing: if you feel these ideas are total trash, then hey, that's cool-- I mean, a little harsh, but, okay-- and I understand if they aren't taken into account during design/implementation. I'm not able to write go
, so it's not like I can contribute much except use-cases and hypothetical ideas.
... Alright so with all that said, please let me know if there's anything I can do to help. Thanks for reading all this, hope it was beneficial!
I definitely think this should emulate the how service-access is viewed. So agree need to introduce the broker as a level of organization and see how that can clean up the amount of clutter. Thanks for the feedback I'll experiment with a few options and circle back.
@aegershman Here's what I have come up with. Wanting to see if this covers the scenarios and if this UX seems reasonable. All these configs are in cf-mgmt.yml
1) Default setup where all plans are public
enable-service-access: true
service-access: []
2) Making some plans limited
all other plans will be all access
. Any plan for the broker/service that is not listed will remain public access. Any plan listed in limited_access_plans
will be limited to the org names and anything in protected orgs list.
service-access:
- broker: dedicated-mysql-broker
services:
- service: p.mysql
limited_access_plans:
- plan: db-large
orgs:
- cfdev-org
which is equivalent to the following
service-access:
- broker: dedicated-mysql-broker
services:
- service: p.mysql
all_access_plans:
- db-small
- db-medium
limited_access_plans:
- plan: db-large
orgs:
- cfdev-org
3) Having a mix of limited
, no access
and all access
service-access:
- broker: dedicated-mysql-broker
services:
- service: p.mysql
all_access_plans: # available for all orgs
- db-small
no_access_plans: # available to no orgs
- db-medium
limited_access_plans:
- plan: db-large # available to cfdev-org and protected orgs (ie system, etc)
orgs:
- cfdev-org
And example of multiple brokers, services to see configuration will look.
service-access:
- broker: rabbitmq-odb
services:
- service: p.rabbitmq
all_access_plans:
- single-node-3.7
- broker: p-rabbitmq
services:
- service: p-rabbitmq
all_access_plans:
- standard
- broker: dedicated-mysql-broker
services:
- service: p.mysql
all_access_plans:
- db-small
limited_access_plans:
- plan: db-medium
- plan: db-large
orgs:
- cfdev-org
Thanks in advance for the feedback. Been helpful to walk through the scenarios. Trying to balance ease of use vs magic
where if not listed assume that is is public so you can use the format above to be very explicit or to have default behavior match what happens when you install a broker. I could also add a flag to default-service-access:
all | none` to allow customizing this
Give me just a little bit to review this w/ coworkers + mock out what it would be like for our current usage, will get back to you ASAP. Thanks again 👍
@calebwashburn i think this has a lot of potential. For an initial step this would solve a lot of the issues that @aegershman and myself have with managing service access. For an initial first go I think this would work and after using it in practice we would know more what could be refined.
@calebwashburn also I don't want to put you in a position similar to the first implementation of service-access: {}
where now that it's implemented it's harder to change/remove without bumping semver. If you felt it's appropriate to mark this as experimental
we could consume it in 1.0.31+
and give you another round of feedback once we start consuming it at work?
Not trying to tell you how to run your product, just don't want to be whiny or put your features in limbo
I proposed this idea back in #84, you graciously expanded & implemented it, and now, like a brat, I don't use the feature; I'd like to give some usage feedback.
concerns with cf-mgmt workflow:
I can't selective disable one service/service-plan or selectively re-enable it for specific orgs without configuring service access settings for every other org.
For example, in order to selectively-enable the "p.mysql" broker's "cdr-double-xl" plan for a limited number of orgs, I have to "affirm" access for every single org for all the other service plans except "cdr-double-xl", and then only the selected orgs which I want to give access would have "cdr-double-xl" listed.
This makes managing service access a bit unruly, and requires updating every org if a new service broker or service plan is added, changed, or removed.
This is also problematic because the blanket "disable service access" including orgs which aren't managed by cf-mgmt. For example, I have the
system
org whitelisted, so I don't have aconfig/system
definition for it. So when I useservice_access
for other orgs, it disables access for all orgs first, includingsystem
, rendering all services insystem
unavailable.current usage
Currently we use a pipeline called
cf-service-access-mgmt
using the cf-cli-resource. Here's a basic snippet from ourprod
foundation:This pipeline works in a two-step flow:
This works well because I can selectively disable a single plan and re-enable the plan for given orgs, while simultaneously leaving other plans of the service instance alone. So for example, I can disable "cdr-double-xl" in "p.mysql", but that leaves the "db-xlarge", "db-large", etc. plans completely untouched from the global defaults.
ideas
We need an ability to disable specific service brokers or service plans for everyone, and selectively enable them for a few orgs. For everything else we don't explicitly configure, we prefer it to be untouched.
Therefore, it could be beneficial to have a centralized
serviceAccess.yml
which looks similar to the pipeline above, wheredisable:
andenable:
blocks can be defined. I made this up in a few minutes, so I really haven't thought through the implications yet.Don't mean to sound ungrateful or anything, but any thoughts?