diff --git a/CHANGELOG.md b/CHANGELOG.md index 356b8cf447b..e8a2991cbc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ #### New Features * Fix #2287: Add support for V1 and V1Beta1 CustomResourceDefinition +* Fix #2311: Add Support for creating bootstrap project template ### 4.10.3 (2020-07-14) #### Bugs diff --git a/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/ProjectRequestTest.java b/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/ProjectRequestTest.java index e0c5e506dd7..3a064b52197 100644 --- a/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/ProjectRequestTest.java +++ b/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/ProjectRequestTest.java @@ -16,8 +16,11 @@ package io.fabric8.openshift.client.server.mock; +import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.Status; import io.fabric8.kubernetes.api.model.StatusBuilder; +import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder; +import io.fabric8.openshift.api.model.ProjectBuilder; import io.fabric8.openshift.api.model.ProjectRequest; import io.fabric8.openshift.api.model.ProjectRequestBuilder; import io.fabric8.openshift.client.OpenShiftClient; @@ -26,6 +29,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.migrationsupport.rules.EnableRuleMigrationSupport; +import java.net.HttpURLConnection; +import java.util.List; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -58,4 +64,107 @@ public void testCreate() { assertNotNull(result); assertEquals(req1, result); } + + @Test + void testCreateUsingParameters() { + // Given + String name = "test-project"; + String displayName = "test-project"; + String description = "test project"; + String requestingUser = "request-user"; + String adminUser = "admin-user"; + server.expect().post().withPath("/apis/project.openshift.io/v1/projects") + .andReturn(HttpURLConnection.HTTP_CREATED, new ProjectBuilder() + .withNewMetadata() + .addToAnnotations("openshift.io/description", description) + .addToAnnotations("openshift.io/display-name", displayName) + .addToAnnotations("openshift.io/requester", requestingUser) + .withName("test-project") + .endMetadata() + .build()).once(); + server.expect().post().withPath("/apis/rbac.authorization.k8s.io/v1/namespaces/test-project/rolebindings") + .andReturn(HttpURLConnection.HTTP_CREATED, new RoleBindingBuilder() + .withNewMetadata() + .addToAnnotations("openshift.io/description", "Allows all pods in this namespace to pull images from this namespace. It is auto-managed by a controller; remove subjects to disable.") + .withName("system:image-pullers") + .withNamespace(name) + .endMetadata() + .withNewRoleRef() + .withApiGroup("rbac.authorization.k8s.io") + .withKind("ClusterRole") + .withName("system:image-puller") + .endRoleRef() + .addNewSubject() + .withApiGroup("rbac.authorization.k8s.io") + .withKind("Group") + .withName("system:serviceaccounts:" + name) + .endSubject() + .build()).once(); + server.expect().post().withPath("/apis/rbac.authorization.k8s.io/v1/namespaces/test-project/rolebindings") + .andReturn(HttpURLConnection.HTTP_CREATED, new RoleBindingBuilder() + .withNewMetadata() + .addToAnnotations("openshift.io/description", "Allows builds in this namespace to push images to" + + "this namespace. It is auto-managed by a controller; remove subjects to disable.") + .withName("system:image-builders") + .withNamespace(name) + .endMetadata() + .withNewRoleRef() + .withApiGroup("rbac.authorization.k8s.io") + .withKind("ClusterRole") + .withName("system:image-builder") + .endRoleRef() + .addNewSubject() + .withKind("ServiceAccount") + .withName("builder") + .withNamespace(name) + .endSubject() + .build()).once(); + server.expect().post().withPath("/apis/rbac.authorization.k8s.io/v1/namespaces/test-project/rolebindings") + .andReturn(HttpURLConnection.HTTP_CREATED, new RoleBindingBuilder() + .withNewMetadata() + .addToAnnotations("openshift.io/description", " Allows deploymentconfigs in this namespace to rollout" + + " pods in this namespace. It is auto-managed by a controller; remove subjects" + + " to disable.") + .withName("system:deployers") + .withNamespace(name) + .endMetadata() + .withNewRoleRef() + .withApiGroup("rbac.authorization.k8s.io") + .withKind("ClusterRole") + .withName("system:deployer") + .endRoleRef() + .addNewSubject() + .withKind("ServiceAccount") + .withName("deployer") + .withNamespace(name) + .endSubject() + .build()).once(); + server.expect().post().withPath("/apis/rbac.authorization.k8s.io/v1/namespaces/test-project/rolebindings") + .andReturn(HttpURLConnection.HTTP_CREATED, new RoleBindingBuilder() + .withNewMetadata() + .withName("admin") + .withNamespace(name) + .endMetadata() + .withNewRoleRef() + .withApiGroup("rbac.authorization.k8s.io") + .withKind("ClusterRole") + .withName("admin") + .endRoleRef() + .addNewSubject() + .withApiGroup("rbac.authorization.k8s.io") + .withKind("User") + .withName(adminUser) + .endSubject() + .build()).once(); + + + OpenShiftClient client = server.getOpenshiftClient(); + + // When + List result = client.projectrequests().create(name, description, displayName, adminUser, requestingUser); + + // Then + assertNotNull(result); + assertEquals(5, result.size()); + } } diff --git a/openshift-client/src/main/java/io/fabric8/openshift/client/dsl/ProjectRequestOperation.java b/openshift-client/src/main/java/io/fabric8/openshift/client/dsl/ProjectRequestOperation.java index 96867077c6f..c072e37d720 100644 --- a/openshift-client/src/main/java/io/fabric8/openshift/client/dsl/ProjectRequestOperation.java +++ b/openshift-client/src/main/java/io/fabric8/openshift/client/dsl/ProjectRequestOperation.java @@ -15,15 +15,27 @@ */ package io.fabric8.openshift.client.dsl; +import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.Status; import io.fabric8.kubernetes.client.dsl.Createable; import io.fabric8.kubernetes.client.dsl.Listable; import io.fabric8.openshift.api.model.DoneableProjectRequest; import io.fabric8.openshift.api.model.ProjectRequest; +import java.util.List; + public interface ProjectRequestOperation extends Createable, Listable { - - + /** + * Creating Bootstrap Project Template + * + * @param name project name + * @param description project description + * @param displayName project display name + * @param adminUser project admin user + * @param requestingUser project requesting user + * @return list of items created + */ + List create(String name, String description, String displayName, String adminUser, String requestingUser); } diff --git a/openshift-client/src/main/java/io/fabric8/openshift/client/dsl/internal/ProjectRequestsOperationImpl.java b/openshift-client/src/main/java/io/fabric8/openshift/client/dsl/internal/ProjectRequestsOperationImpl.java index e7becbffdf5..53577904ff3 100644 --- a/openshift-client/src/main/java/io/fabric8/openshift/client/dsl/internal/ProjectRequestsOperationImpl.java +++ b/openshift-client/src/main/java/io/fabric8/openshift/client/dsl/internal/ProjectRequestsOperationImpl.java @@ -15,11 +15,17 @@ */ package io.fabric8.openshift.client.dsl.internal; +import io.fabric8.kubernetes.api.model.DeletionPropagation; +import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.ListOptions; import io.fabric8.kubernetes.api.model.ListOptionsBuilder; +import io.fabric8.kubernetes.api.model.rbac.RoleBinding; +import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder; import io.fabric8.kubernetes.client.dsl.base.OperationContext; -import io.fabric8.kubernetes.client.utils.URLUtils; +import io.fabric8.kubernetes.client.dsl.internal.NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl; import io.fabric8.kubernetes.client.utils.Utils; +import io.fabric8.openshift.api.model.Project; +import io.fabric8.openshift.api.model.ProjectBuilder; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -34,6 +40,8 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.ExecutionException; import static io.fabric8.openshift.client.OpenShiftAPIGroups.PROJECT; @@ -165,4 +173,114 @@ public Status list(ListOptions listOptions) { public ProjectRequest getItem() { return (ProjectRequest) context.getItem(); } + + @Override + public List create(String name, String description, String displayName, String adminUser, String requestingUser) { + List result = new ArrayList<>(); + Project project = getProject(name, description, displayName, requestingUser); + List projectRoleBindings = getNewProjectRoleBindings(name, adminUser); + + // Create Project + ProjectOperationsImpl projectOperations = new ProjectOperationsImpl(client, OpenShiftConfig.wrap(config)); + result.add(projectOperations.create(project)); + + // Create Role Bindings + NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl listOp = new NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl(client, config, getNamespace(), null, false, false, new ArrayList<>(), projectRoleBindings, null, DeletionPropagation.BACKGROUND, true) {}; + result.addAll(listOp.createOrReplace()); + + return result; + } + + private Project getProject(String name, String description, String displayName, String requestingUser) { + return new ProjectBuilder() + .withNewMetadata() + .addToAnnotations("openshift.io/description", description) + .addToAnnotations("openshift.io/display-name", displayName) + .addToAnnotations("openshift.io/requester", requestingUser) + .withName(name) + .endMetadata() + .build(); + } + + private List getNewProjectRoleBindings(String name, String adminUser) { + RoleBinding roleBindingPuller = new RoleBindingBuilder() + .withNewMetadata() + .addToAnnotations("openshift.io/description", "Allows all pods in this namespace to pull images from this namespace. It is auto-managed by a controller; remove subjects to disable.") + .withName("system:image-pullers") + .withNamespace(name) + .endMetadata() + .withNewRoleRef() + .withApiGroup("rbac.authorization.k8s.io") + .withKind("ClusterRole") + .withName("system:image-puller") + .endRoleRef() + .addNewSubject() + .withApiGroup("rbac.authorization.k8s.io") + .withKind("Group") + .withName("system:serviceaccounts:" + name) + .endSubject() + .build(); + RoleBinding roleBindingBuilder = new RoleBindingBuilder() + .withNewMetadata() + .addToAnnotations("openshift.io/description", "Allows builds in this namespace to push images to" + + "this namespace. It is auto-managed by a controller; remove subjects to disable.") + .withName("system:image-builders") + .withNamespace(name) + .endMetadata() + .withNewRoleRef() + .withApiGroup("rbac.authorization.k8s.io") + .withKind("ClusterRole") + .withName("system:image-builder") + .endRoleRef() + .addNewSubject() + .withKind("ServiceAccount") + .withName("builder") + .withNamespace(name) + .endSubject() + .build(); + RoleBinding roleBindingDeployer = new RoleBindingBuilder() + .withNewMetadata() + .addToAnnotations("openshift.io/description", " Allows deploymentconfigs in this namespace to rollout" + + " pods in this namespace. It is auto-managed by a controller; remove subjects" + + " to disable.") + .withName("system:deployers") + .withNamespace(name) + .endMetadata() + .withNewRoleRef() + .withApiGroup("rbac.authorization.k8s.io") + .withKind("ClusterRole") + .withName("system:deployer") + .endRoleRef() + .addNewSubject() + .withKind("ServiceAccount") + .withName("deployer") + .withNamespace(name) + .endSubject() + .build(); + + RoleBinding roleBindingAdmin = new RoleBindingBuilder() + .withNewMetadata() + .withName("admin") + .withNamespace(name) + .endMetadata() + .withNewRoleRef() + .withApiGroup("rbac.authorization.k8s.io") + .withKind("ClusterRole") + .withName("admin") + .endRoleRef() + .addNewSubject() + .withApiGroup("rbac.authorization.k8s.io") + .withKind("User") + .withName(adminUser) + .endSubject() + .build(); + + List resources = new ArrayList<>(); + resources.add(roleBindingPuller); + resources.add(roleBindingBuilder); + resources.add(roleBindingDeployer); + resources.add(roleBindingAdmin); + + return resources; + } }