bbende commented on a change in pull request #4450: URL: https://github.com/apache/nifi/pull/4450#discussion_r465727136
########## File path: nifi-docs/src/main/asciidoc/toolkit-guide.adoc ########## @@ -94,10 +94,42 @@ The following are available commands: nifi pg-get-services nifi pg-enable-services nifi pg-disable-services + nifi pg-create-service + nifi create-user + nifi list-users + nifi create-user-group + nifi list-user-groups + nifi update-user-group + nifi get-policy + nifi update-policy + nifi create-service + nifi get-services + nifi get-service + nifi disable-services + nifi enable-services + nifi get-reporting-task + nifi get-reporting-tasks + nifi create-reporting-task + nifi set-param + nifi delete-param + nifi list-param-contexts + nifi get-param-context + nifi create-param-context + nifi delete-param-context + nifi merge-param-context + nifi import-param-context + nifi pg-get-param-context + nifi pg-set-param-context + nifi list-templates + nifi download-template + nifi upload-template + nifi start-reporting-tasks + nifi stop-reporting-tasks registry current-user registry list-buckets registry create-bucket registry delete-bucket + registry update-bucket-policy Review comment: SInce we are updating this, there are other registry commands that got added for users/groups/policies that never made it into this list. Can we add those? ########## File path: nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/CommandOption.java ########## @@ -24,6 +24,8 @@ public enum CommandOption { // General + CONNECTION_TIMEOUT("cto", "connectionTimeout", "Timeout parameter for creating a connection to NiFi/Registry", true), + READ_TIMEOUT("rto", "readTimeout", "Timeout parameter for reading from NiFi/Registry", true), Review comment: Can we add to the description of these to say that the value is in milliseconds? ########## File path: nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/bucket/UpdateBucketPolicy.java ########## @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.nifi.toolkit.cli.impl.command.registry.bucket; + +import org.apache.commons.cli.ParseException; +import org.apache.nifi.registry.authorization.AccessPolicy; +import org.apache.nifi.registry.authorization.Tenant; +import org.apache.nifi.registry.bucket.Bucket; +import org.apache.nifi.registry.client.NiFiRegistryClient; +import org.apache.nifi.registry.client.NiFiRegistryException; +import org.apache.nifi.toolkit.cli.api.Context; +import org.apache.nifi.toolkit.cli.impl.client.ExtendedNiFiRegistryClient; +import org.apache.nifi.toolkit.cli.impl.client.registry.PoliciesClient; +import org.apache.nifi.toolkit.cli.impl.command.CommandOption; +import org.apache.nifi.toolkit.cli.impl.command.registry.AbstractNiFiRegistryCommand; +import org.apache.nifi.toolkit.cli.impl.command.registry.tenant.TenantHelper; +import org.apache.nifi.toolkit.cli.impl.result.VoidResult; +import org.apache.nifi.util.StringUtils; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Optional; +import java.util.Properties; +import java.util.Set; + +public class UpdateBucketPolicy extends AbstractNiFiRegistryCommand<VoidResult> { + + + public UpdateBucketPolicy() { + super("update-bucket-policy", VoidResult.class); + } + + @Override + public String getDescription() { + return "Updates access policy of bucket"; + } + + @Override + public void doInitialize(final Context context) { + addOption(CommandOption.BUCKET_NAME.createOption()); + addOption(CommandOption.BUCKET_ID.createOption()); + addOption(CommandOption.USER_NAME_LIST.createOption()); + addOption(CommandOption.USER_ID_LIST.createOption()); + addOption(CommandOption.GROUP_NAME_LIST.createOption()); + addOption(CommandOption.GROUP_ID_LIST.createOption()); + addOption(CommandOption.POLICY_ACTION.createOption()); + } + + + @Override + public VoidResult doExecute(NiFiRegistryClient client, Properties properties) throws IOException, NiFiRegistryException, ParseException { + if (!(client instanceof ExtendedNiFiRegistryClient)) { + throw new IllegalArgumentException("This command needs extended registry client!"); + } + final ExtendedNiFiRegistryClient extendedClient = (ExtendedNiFiRegistryClient) client; + final PoliciesClient policiesClient = extendedClient.getPoliciesClient(); + + final String bucketName = getArg(properties, CommandOption.BUCKET_NAME); + String bucketId = getArg(properties, CommandOption.BUCKET_ID); + + final String userNames = getArg(properties, CommandOption.USER_NAME_LIST); + final String userIds = getArg(properties, CommandOption.USER_ID_LIST); + final String groupNames = getArg(properties, CommandOption.GROUP_NAME_LIST); + final String groupIds = getArg(properties, CommandOption.GROUP_ID_LIST); + + final String policyAction = getRequiredArg(properties, CommandOption.POLICY_ACTION); + final HashSet<String> permittedActions = new HashSet<>(Arrays.asList("read", "write", "delete")); + if (!permittedActions.contains(policyAction)) { + throw new IllegalArgumentException("Only read, write, delete actions permitted"); + } + if (StringUtils.isBlank(bucketName) == StringUtils.isBlank(bucketId)) { + throw new IllegalArgumentException("Specify either bucket name or bucket id"); + } + if (StringUtils.isBlank(bucketId)) { + final Optional<Bucket> optionalBucket = client.getBucketClient().getAll() + .stream().filter(b -> bucketName.equals(b.getName())).findAny(); + if (!optionalBucket.isPresent()) { + throw new IllegalArgumentException("Specified bucket does not exist"); + } + bucketId = optionalBucket.get().getIdentifier(); + } else { + try { + extendedClient.getBucketClient().get(bucketId); + } catch (NiFiRegistryException e) { + throw new IllegalArgumentException("Specified bucket does not exist"); + } + } + AccessPolicy accessPolicy; + String resource = "/buckets/" + bucketId; + try { + accessPolicy = policiesClient.getAccessPolicy(policyAction, resource); + } catch (NiFiRegistryException e) { + accessPolicy = new AccessPolicy(); + accessPolicy.setResource(resource); + accessPolicy.setAction(policyAction); + } + if (!StringUtils.isBlank(userNames) || !StringUtils.isBlank(userIds)) { + Set<Tenant> users = TenantHelper.selectExistingTenants(userNames, + userIds, extendedClient.getTenantsClient().getUsers()); + accessPolicy.setUsers(users); Review comment: We may want to document that when updating the users it will overwrite any existing users, so if your goal is to add one user to an existing set of users, you need to send in all of them. We have a little bit of an inconsistency between the NiFi command for UpdatePolicy and NiFi Registry command for CreateOrUpdateAccessPolicy. The NiFi command has an argument for "overwrite" which determines whether the set of users/groups is overwritten or added to, where as the NiFi Registry command works the same as your command where it is always an overwrite. ########## File path: nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/command/registry/bucket/UpdateBucketPolicy.java ########## @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.nifi.toolkit.cli.impl.command.registry.bucket; + +import org.apache.commons.cli.ParseException; +import org.apache.nifi.registry.authorization.AccessPolicy; +import org.apache.nifi.registry.authorization.Tenant; +import org.apache.nifi.registry.bucket.Bucket; +import org.apache.nifi.registry.client.NiFiRegistryClient; +import org.apache.nifi.registry.client.NiFiRegistryException; +import org.apache.nifi.toolkit.cli.api.Context; +import org.apache.nifi.toolkit.cli.impl.client.ExtendedNiFiRegistryClient; +import org.apache.nifi.toolkit.cli.impl.client.registry.PoliciesClient; +import org.apache.nifi.toolkit.cli.impl.command.CommandOption; +import org.apache.nifi.toolkit.cli.impl.command.registry.AbstractNiFiRegistryCommand; +import org.apache.nifi.toolkit.cli.impl.command.registry.tenant.TenantHelper; +import org.apache.nifi.toolkit.cli.impl.result.VoidResult; +import org.apache.nifi.util.StringUtils; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Optional; +import java.util.Properties; +import java.util.Set; + +public class UpdateBucketPolicy extends AbstractNiFiRegistryCommand<VoidResult> { + + + public UpdateBucketPolicy() { + super("update-bucket-policy", VoidResult.class); + } + + @Override + public String getDescription() { + return "Updates access policy of bucket"; + } + + @Override + public void doInitialize(final Context context) { + addOption(CommandOption.BUCKET_NAME.createOption()); + addOption(CommandOption.BUCKET_ID.createOption()); + addOption(CommandOption.USER_NAME_LIST.createOption()); + addOption(CommandOption.USER_ID_LIST.createOption()); + addOption(CommandOption.GROUP_NAME_LIST.createOption()); + addOption(CommandOption.GROUP_ID_LIST.createOption()); + addOption(CommandOption.POLICY_ACTION.createOption()); + } + + + @Override + public VoidResult doExecute(NiFiRegistryClient client, Properties properties) throws IOException, NiFiRegistryException, ParseException { + if (!(client instanceof ExtendedNiFiRegistryClient)) { + throw new IllegalArgumentException("This command needs extended registry client!"); + } + final ExtendedNiFiRegistryClient extendedClient = (ExtendedNiFiRegistryClient) client; + final PoliciesClient policiesClient = extendedClient.getPoliciesClient(); + + final String bucketName = getArg(properties, CommandOption.BUCKET_NAME); + String bucketId = getArg(properties, CommandOption.BUCKET_ID); + + final String userNames = getArg(properties, CommandOption.USER_NAME_LIST); + final String userIds = getArg(properties, CommandOption.USER_ID_LIST); + final String groupNames = getArg(properties, CommandOption.GROUP_NAME_LIST); + final String groupIds = getArg(properties, CommandOption.GROUP_ID_LIST); + + final String policyAction = getRequiredArg(properties, CommandOption.POLICY_ACTION); + final HashSet<String> permittedActions = new HashSet<>(Arrays.asList("read", "write", "delete")); + if (!permittedActions.contains(policyAction)) { + throw new IllegalArgumentException("Only read, write, delete actions permitted"); + } + if (StringUtils.isBlank(bucketName) == StringUtils.isBlank(bucketId)) { + throw new IllegalArgumentException("Specify either bucket name or bucket id"); + } + if (StringUtils.isBlank(bucketId)) { + final Optional<Bucket> optionalBucket = client.getBucketClient().getAll() + .stream().filter(b -> bucketName.equals(b.getName())).findAny(); + if (!optionalBucket.isPresent()) { + throw new IllegalArgumentException("Specified bucket does not exist"); + } + bucketId = optionalBucket.get().getIdentifier(); + } else { + try { + extendedClient.getBucketClient().get(bucketId); + } catch (NiFiRegistryException e) { + throw new IllegalArgumentException("Specified bucket does not exist"); + } + } + AccessPolicy accessPolicy; + String resource = "/buckets/" + bucketId; + try { + accessPolicy = policiesClient.getAccessPolicy(policyAction, resource); + } catch (NiFiRegistryException e) { + accessPolicy = new AccessPolicy(); + accessPolicy.setResource(resource); + accessPolicy.setAction(policyAction); + } + if (!StringUtils.isBlank(userNames) || !StringUtils.isBlank(userIds)) { + Set<Tenant> users = TenantHelper.selectExistingTenants(userNames, + userIds, extendedClient.getTenantsClient().getUsers()); + accessPolicy.setUsers(users); + } + if (!StringUtils.isBlank(groupNames) || !StringUtils.isBlank(groupIds)) { + Set<Tenant> groups = TenantHelper.selectExistingTenants(groupNames, + groupIds, extendedClient.getTenantsClient().getUserGroups()); + accessPolicy.setUserGroups(groups); + } + AccessPolicy updatedPolicy = StringUtils.isBlank(accessPolicy.getIdentifier()) + ? policiesClient.createAccessPolicy(accessPolicy) + : policiesClient.updateAccessPolicy(accessPolicy); + println(updatedPolicy.getIdentifier()); + return VoidResult.getInstance(); Review comment: If we want the result to be void, then we should wrap the println with `if (shouldPrint(properties)) { ... }`, this would make it only print when in interactive mode of the CLI, but not during non-interactive mode. If you want the command to always return the policy id, then instead of println with Void, you would instead return a StringResult like: `return new StringResult(identifier, getContext().isInteractive());` Usually a create command returns the id as a string result and an update returns void, so since this command is a combo of either create or update, you could return different results depending whether you called create or update. ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org