Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #2311: Add Support for creating bootstrap project template #2376

Merged
merged 1 commit into from Aug 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Expand Up @@ -33,5 +33,5 @@ jobs:
uses: actions/setup-java@v1
with:
java-version: '11'
- name: Check License Headers
- name: Build Project
run: mvn clean install
2 changes: 1 addition & 1 deletion .github/workflows/javadocs.yml
Expand Up @@ -33,5 +33,5 @@ jobs:
uses: actions/setup-java@v1
with:
java-version: '11'
- name: Check License Headers
- name: Check Java Docs
run: mvn clean install javadoc:jar -DskipTests -Pjavadoc-test
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -15,6 +15,7 @@
* Fix #2292: Update createOrReplace to do replace when create fails with conflict

#### New Features
* Fix #2311: Add Support for creating bootstrap project template
* Fix #2287: Add support for V1 and V1Beta1 CustomResourceDefinition
* Fix #2319: Create Config without using auto-configure functionality or setting env variables

Expand Down
Expand Up @@ -373,6 +373,7 @@ public void onDelete(ClusterRoleBinding oldObj, boolean deletedFinalStateUnknown
factory.startAllRegisteredInformers();

foundExistingClusterRoleBinding.await(LATCH_AWAIT_PERIOD_IN_SECONDS, TimeUnit.SECONDS);
waitUntilResourceVersionSynced();
assertEquals(0, foundExistingClusterRoleBinding.getCount());
assertEquals(endResourceVersion, clusterRoleBindingSharedIndexInformer.lastSyncResourceVersion());

Expand Down
Expand Up @@ -16,6 +16,8 @@

package io.fabric8.openshift.client.server.mock;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder;
import io.fabric8.openshift.api.model.Project;
import io.fabric8.openshift.api.model.ProjectBuilder;
import io.fabric8.openshift.api.model.ProjectList;
Expand All @@ -26,6 +28,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.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
Expand Down Expand Up @@ -93,4 +98,107 @@ public void testDelete() {
deleted = client.projects().withName("project3").delete();
assertFalse(deleted);
}

@Test
void testCreateProjectAndRoleBindings() {
// 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<HasMetadata> result = client.projects().createProjectAndRoleBindings(name, description, displayName, adminUser, requestingUser);

// Then
assertNotNull(result);
assertEquals(5, result.size());
}
}
Expand Up @@ -73,7 +73,6 @@
import io.fabric8.openshift.api.model.DoneableClusterRoleBinding;
import io.fabric8.openshift.api.model.DoneableRole;
import io.fabric8.openshift.api.model.DoneableRoleBinding;
import io.fabric8.openshift.api.model.DoneableProject;
import io.fabric8.openshift.api.model.DoneableRoute;
import io.fabric8.openshift.api.model.DoneableSecurityContextConstraints;
import io.fabric8.openshift.api.model.DoneableTemplate;
Expand All @@ -96,8 +95,6 @@
import io.fabric8.openshift.api.model.RoleBinding;
import io.fabric8.openshift.api.model.RoleBindingList;
import io.fabric8.openshift.api.model.RoleList;
import io.fabric8.openshift.api.model.Project;
import io.fabric8.openshift.api.model.ProjectList;
import io.fabric8.openshift.api.model.Route;
import io.fabric8.openshift.api.model.RouteList;
import io.fabric8.openshift.api.model.SecurityContextConstraints;
Expand Down Expand Up @@ -434,7 +431,7 @@ public NonNamespaceOperation<OAuthClient, OAuthClientList, DoneableOAuthClient,
}

@Override
public NonNamespaceOperation<Project, ProjectList, DoneableProject, Resource<Project, DoneableProject>> projects() {
public ProjectOperation projects() {
return new ProjectOperationsImpl(httpClient, OpenShiftConfig.wrap(getConfiguration()));
}

Expand Down
Expand Up @@ -32,7 +32,6 @@
import io.fabric8.openshift.api.model.DoneableOAuthAccessToken;
import io.fabric8.openshift.api.model.DoneableOAuthAuthorizeToken;
import io.fabric8.openshift.api.model.DoneableOAuthClient;
import io.fabric8.openshift.api.model.DoneableProject;
import io.fabric8.openshift.api.model.DoneableRole;
import io.fabric8.openshift.api.model.DoneableRoleBinding;
import io.fabric8.openshift.api.model.DoneableRoute;
Expand Down Expand Up @@ -85,7 +84,7 @@ public interface OpenShiftClient extends KubernetesClient {

NonNamespaceOperation<OAuthClient, OAuthClientList, DoneableOAuthClient, Resource<OAuthClient, DoneableOAuthClient>> oAuthClients();

NonNamespaceOperation<Project, ProjectList, DoneableProject, Resource<Project, DoneableProject>> projects();
ProjectOperation projects();

ProjectRequestOperation projectrequests();

Expand Down
@@ -0,0 +1,39 @@
/**
* Copyright (C) 2015 Red Hat, Inc.
*
* Licensed 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 io.fabric8.openshift.client.dsl;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation;
import io.fabric8.kubernetes.client.dsl.Resource;
import io.fabric8.openshift.api.model.DoneableProject;
import io.fabric8.openshift.api.model.Project;
import io.fabric8.openshift.api.model.ProjectList;

import java.util.List;

public interface ProjectOperation extends NonNamespaceOperation<Project, ProjectList, DoneableProject, Resource<Project, DoneableProject>> {
/**
* 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<HasMetadata> createProjectAndRoleBindings(String name, String description, String displayName, String adminUser, String requestingUser);
}
Expand Up @@ -24,6 +24,4 @@
public interface ProjectRequestOperation extends
Createable<ProjectRequest, ProjectRequest, DoneableProjectRequest>,
Listable<Status> {


}
Expand Up @@ -15,21 +15,34 @@
*/
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.rbac.RoleBinding;
import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder;
import io.fabric8.kubernetes.client.dsl.Resource;
import io.fabric8.kubernetes.client.dsl.base.OperationContext;
import io.fabric8.kubernetes.client.dsl.internal.NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl;
import io.fabric8.openshift.api.model.ProjectBuilder;
import io.fabric8.openshift.client.dsl.ProjectOperation;
import okhttp3.OkHttpClient;
import io.fabric8.openshift.api.model.DoneableProject;
import io.fabric8.openshift.api.model.Project;
import io.fabric8.openshift.api.model.ProjectList;
import io.fabric8.openshift.client.OpenShiftConfig;

import java.util.Map;
import java.util.TreeMap;
import java.util.ArrayList;
import java.util.List;

import static io.fabric8.openshift.client.OpenShiftAPIGroups.PROJECT;

public class ProjectOperationsImpl extends OpenShiftOperation<Project, ProjectList, DoneableProject,
Resource<Project, DoneableProject>> {
Resource<Project, DoneableProject>> implements ProjectOperation {
public static final String OPENSHIFT_IO_DESCRIPTION_ANNOTATION = "openshift.io/description";
public static final String OPENSHIFT_IO_DISPLAY_NAME_ANNOTATION = "openshift.io/display-name";
public static final String OPENSHIFT_IO_REQUESTER_ANNOTATION = "openshift.io/requester";
public static final String RBAC_AUTHORIZATION_APIGROUP = "rbac.authorization.k8s.io";
public static final String CLUSTER_ROLE = "ClusterRole";


public ProjectOperationsImpl(OkHttpClient client, OpenShiftConfig config) {
this(new OperationContext().withOkhttpClient(client).withConfig(config));
Expand All @@ -51,4 +64,113 @@ public ProjectOperationsImpl newInstance(OperationContext context) {
public boolean isResourceNamespaced() {
return false;
}

@Override
public List<HasMetadata> createProjectAndRoleBindings(String name, String description, String displayName, String adminUser, String requestingUser) {
List<HasMetadata> result = new ArrayList<>();
Project project = initProject(name, description, displayName, requestingUser);
List<HasMetadata> projectRoleBindings = initRoleBindings(name, adminUser);

// Create Project
result.add(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 initProject(String name, String description, String displayName, String requestingUser) {
return new ProjectBuilder()
.withNewMetadata()
.addToAnnotations(OPENSHIFT_IO_DESCRIPTION_ANNOTATION, description)
.addToAnnotations(OPENSHIFT_IO_DISPLAY_NAME_ANNOTATION, displayName)
.addToAnnotations(OPENSHIFT_IO_REQUESTER_ANNOTATION, requestingUser)
.withName(name)
.endMetadata()
.build();
}

private List<HasMetadata> initRoleBindings(String name, String adminUser) {
RoleBinding roleBindingPuller = new RoleBindingBuilder()
.withNewMetadata()
.addToAnnotations(OPENSHIFT_IO_DESCRIPTION_ANNOTATION, "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_APIGROUP)
.withKind(CLUSTER_ROLE)
.withName("system:image-puller")
.endRoleRef()
.addNewSubject()
.withApiGroup(RBAC_AUTHORIZATION_APIGROUP)
.withKind("Group")
.withName("system:serviceaccounts:" + name)
.endSubject()
.build();
RoleBinding roleBindingBuilder = new RoleBindingBuilder()
.withNewMetadata()
.addToAnnotations(OPENSHIFT_IO_DESCRIPTION_ANNOTATION, "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_APIGROUP)
.withKind(CLUSTER_ROLE)
.withName("system:image-builder")
.endRoleRef()
.addNewSubject()
.withKind("ServiceAccount")
.withName("builder")
.withNamespace(name)
.endSubject()
.build();
RoleBinding roleBindingDeployer = new RoleBindingBuilder()
.withNewMetadata()
.addToAnnotations(OPENSHIFT_IO_DESCRIPTION_ANNOTATION, " 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_APIGROUP)
.withKind(CLUSTER_ROLE)
.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_APIGROUP)
.withKind(CLUSTER_ROLE)
.withName("admin")
.endRoleRef()
.addNewSubject()
.withApiGroup(RBAC_AUTHORIZATION_APIGROUP)
.withKind("User")
.withName(adminUser)
.endSubject()
.build();

List<HasMetadata> resources = new ArrayList<>();
resources.add(roleBindingPuller);
resources.add(roleBindingBuilder);
resources.add(roleBindingDeployer);
resources.add(roleBindingAdmin);

return resources;
}
}