0
# Project Operations
1
2
This document covers OpenShift project operations, including project creation with role bindings, project requests, and project management.
3
4
## Core Imports
5
6
```java { .api }
7
import io.fabric8.openshift.client.OpenShiftClient;
8
import io.fabric8.openshift.client.dsl.ProjectOperation;
9
import io.fabric8.openshift.client.dsl.ProjectRequestOperation;
10
import io.fabric8.kubernetes.api.model.Namespace;
11
import io.fabric8.kubernetes.api.model.NamespaceList;
12
import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation;
13
import io.fabric8.kubernetes.client.dsl.Resource;
14
```
15
16
## Project Operations
17
18
OpenShift projects extend Kubernetes namespaces with additional OpenShift-specific functionality, including role-based access control and resource quotas.
19
20
### Basic Project Operations
21
22
```java { .api }
23
// List all projects (equivalent to namespaces with OpenShift metadata)
24
List<Namespace> projects = client.projects().list().getItems();
25
26
// Get a specific project
27
Namespace project = client.projects()
28
.withName("my-project")
29
.get();
30
31
// Check if project exists
32
boolean exists = client.projects()
33
.withName("my-project")
34
.get() != null;
35
```
36
37
### Creating Projects
38
39
```java { .api }
40
// Create a simple project (namespace)
41
Namespace simpleProject = client.projects()
42
.create(new NamespaceBuilder()
43
.withNewMetadata()
44
.withName("simple-project")
45
.addToLabels("type", "development")
46
.endMetadata()
47
.build());
48
49
// Create project with display name and description
50
Namespace projectWithMetadata = client.projects()
51
.create(new NamespaceBuilder()
52
.withNewMetadata()
53
.withName("my-application")
54
.addToAnnotations("openshift.io/display-name", "My Application")
55
.addToAnnotations("openshift.io/description", "Development project for my application")
56
.addToLabels("environment", "development")
57
.endMetadata()
58
.build());
59
```
60
61
### Project Creation with Role Bindings
62
63
```java { .api }
64
// Create project with automatic role bindings
65
Namespace projectWithRoles = client.projects()
66
.createProjectAndRoleBindings(
67
"team-project", // project name
68
"Team Development Project", // description
69
"Team Project", // display name
70
"developer-user" // admin user
71
);
72
73
// Create project with multiple administrators
74
Namespace multiAdminProject = client.projects()
75
.createProjectAndRoleBindings(
76
"multi-admin-project",
77
"Multi-administrator project",
78
"Multi Admin Project",
79
"admin-user1,admin-user2" // comma-separated admin users
80
);
81
```
82
83
### Project Deletion and Cleanup
84
85
```java { .api }
86
// Delete a project (this will delete the namespace and all resources)
87
Boolean deleted = client.projects()
88
.withName("obsolete-project")
89
.delete();
90
91
// Delete project with grace period
92
Boolean gracefullyDeleted = client.projects()
93
.withName("project-to-delete")
94
.withGracePeriod(30) // 30 seconds
95
.delete();
96
97
// Force delete project (immediate deletion)
98
Boolean forceDeleted = client.projects()
99
.withName("stuck-project")
100
.withGracePeriod(0)
101
.delete();
102
```
103
104
## ProjectRequest Operations
105
106
ProjectRequest is used to request the creation of new projects, typically by regular users who don't have cluster-admin privileges.
107
108
### Creating Project Requests
109
110
```java { .api }
111
// Create a project request (for non-admin users)
112
ProjectRequest projectRequest = new ProjectRequestBuilder()
113
.withNewMetadata()
114
.withName("requested-project")
115
.endMetadata()
116
.withDisplayName("Requested Project")
117
.withDescription("Project requested by developer")
118
.build();
119
120
// Submit project request
121
ProjectRequest submittedRequest = client.projectrequests()
122
.create(projectRequest);
123
124
// The project request will create a project if the user has permission
125
Namespace createdProject = client.projects()
126
.withName("requested-project")
127
.get();
128
```
129
130
### Project Request with Custom Settings
131
132
```java { .api }
133
// Project request with detailed metadata
134
ProjectRequest detailedRequest = new ProjectRequestBuilder()
135
.withNewMetadata()
136
.withName("detailed-project")
137
.addToAnnotations("openshift.io/requester", "john.doe")
138
.endMetadata()
139
.withDisplayName("Detailed Development Project")
140
.withDescription("Comprehensive project for application development")
141
.build();
142
143
ProjectRequest created = client.projectrequests()
144
.create(detailedRequest);
145
```
146
147
## Project Management
148
149
### Project Monitoring and Status
150
151
```java { .api }
152
// Watch project changes
153
client.projects()
154
.watch(new Watcher<Namespace>() {
155
@Override
156
public void eventReceived(Action action, Namespace project) {
157
System.out.println("Project " + action + ": " +
158
project.getMetadata().getName());
159
160
String displayName = project.getMetadata().getAnnotations()
161
.get("openshift.io/display-name");
162
if (displayName != null) {
163
System.out.println(" Display Name: " + displayName);
164
}
165
}
166
167
@Override
168
public void onClose(WatcherException cause) {
169
System.out.println("Project watch closed: " + cause.getMessage());
170
}
171
});
172
173
// Get project status and phase
174
Namespace project = client.projects()
175
.withName("my-project")
176
.get();
177
178
String phase = project.getStatus().getPhase(); // Active, Terminating
179
System.out.println("Project phase: " + phase);
180
```
181
182
### Project Metadata Management
183
184
```java { .api }
185
// Update project annotations and labels
186
Namespace updatedProject = client.projects()
187
.withName("my-project")
188
.edit(project -> new NamespaceBuilder(project)
189
.editMetadata()
190
.addToAnnotations("openshift.io/display-name", "Updated Display Name")
191
.addToAnnotations("openshift.io/description", "Updated description")
192
.addToLabels("team", "backend")
193
.addToLabels("environment", "production")
194
.endMetadata()
195
.build());
196
197
// Remove annotations
198
Namespace cleanedProject = client.projects()
199
.withName("my-project")
200
.edit(project -> new NamespaceBuilder(project)
201
.editMetadata()
202
.removeFromAnnotations("obsolete-annotation")
203
.endMetadata()
204
.build());
205
```
206
207
### Project Resource Management
208
209
```java { .api }
210
// Get all resources in a project
211
client.inNamespace("my-project").pods().list();
212
client.inNamespace("my-project").services().list();
213
client.inNamespace("my-project").deploymentConfigs().list();
214
client.inNamespace("my-project").routes().list();
215
216
// Count resources in project
217
int podCount = client.inNamespace("my-project").pods().list().getItems().size();
218
int serviceCount = client.inNamespace("my-project").services().list().getItems().size();
219
220
System.out.println("Project my-project has " + podCount + " pods and " +
221
serviceCount + " services");
222
```
223
224
## Advanced Project Operations
225
226
### Project Templates and Initialization
227
228
```java { .api }
229
// Initialize project with template
230
public void initializeProjectFromTemplate(String projectName, String templateName) {
231
// 1. Create project
232
Namespace project = client.projects()
233
.createProjectAndRoleBindings(
234
projectName,
235
"Project created from template " + templateName,
236
projectName,
237
client.currentUser().getMetadata().getName()
238
);
239
240
// 2. Apply template
241
Template processed = client.templates()
242
.inNamespace("openshift") // Common template namespace
243
.withName(templateName)
244
.withParameter("PROJECT_NAME", projectName)
245
.process();
246
247
// 3. Create objects in the new project
248
for (HasMetadata object : processed.getObjects()) {
249
object.getMetadata().setNamespace(projectName);
250
client.resource(object).createOrReplace();
251
}
252
}
253
```
254
255
### Project Access Control
256
257
```java { .api }
258
// Add user to project with admin role
259
RoleBinding adminBinding = new RoleBindingBuilder()
260
.withNewMetadata()
261
.withName("admin-binding")
262
.withNamespace("my-project")
263
.endMetadata()
264
.withNewRoleRef()
265
.withApiGroup("rbac.authorization.k8s.io")
266
.withKind("ClusterRole")
267
.withName("admin")
268
.endRoleRef()
269
.addNewSubject()
270
.withKind("User")
271
.withName("new-admin-user")
272
.withApiGroup("rbac.authorization.k8s.io")
273
.endSubject()
274
.build();
275
276
client.rbac().roleBindings()
277
.inNamespace("my-project")
278
.create(adminBinding);
279
280
// Add group to project with view role
281
RoleBinding viewBinding = new RoleBindingBuilder()
282
.withNewMetadata()
283
.withName("viewers-binding")
284
.withNamespace("my-project")
285
.endMetadata()
286
.withNewRoleRef()
287
.withApiGroup("rbac.authorization.k8s.io")
288
.withKind("ClusterRole")
289
.withName("view")
290
.endRoleRef()
291
.addNewSubject()
292
.withKind("Group")
293
.withName("developers")
294
.withApiGroup("rbac.authorization.k8s.io")
295
.endSubject()
296
.build();
297
298
client.rbac().roleBindings()
299
.inNamespace("my-project")
300
.create(viewBinding);
301
```
302
303
### Project Resource Quotas
304
305
```java { .api }
306
// Set resource quota for project
307
ResourceQuota quota = new ResourceQuotaBuilder()
308
.withNewMetadata()
309
.withName("project-quota")
310
.withNamespace("my-project")
311
.endMetadata()
312
.withNewSpec()
313
.addToHard("requests.cpu", new Quantity("2"))
314
.addToHard("requests.memory", new Quantity("4Gi"))
315
.addToHard("limits.cpu", new Quantity("4"))
316
.addToHard("limits.memory", new Quantity("8Gi"))
317
.addToHard("persistentvolumeclaims", new Quantity("10"))
318
.addToHard("pods", new Quantity("20"))
319
.addToHard("services", new Quantity("10"))
320
.endSpec()
321
.build();
322
323
client.resourceQuotas()
324
.inNamespace("my-project")
325
.create(quota);
326
327
// Check quota usage
328
ResourceQuota currentQuota = client.resourceQuotas()
329
.inNamespace("my-project")
330
.withName("project-quota")
331
.get();
332
333
Map<String, Quantity> used = currentQuota.getStatus().getUsed();
334
Map<String, Quantity> hard = currentQuota.getStatus().getHard();
335
336
System.out.println("CPU usage: " + used.get("requests.cpu") +
337
" / " + hard.get("requests.cpu"));
338
```
339
340
### Project Network Policies
341
342
```java { .api }
343
// Create network policy to isolate project
344
NetworkPolicy isolationPolicy = new NetworkPolicyBuilder()
345
.withNewMetadata()
346
.withName("deny-all")
347
.withNamespace("my-project")
348
.endMetadata()
349
.withNewSpec()
350
.withNewPodSelector() // Selects all pods
351
.endPodSelector()
352
.withPolicyTypes("Ingress", "Egress")
353
// Empty ingress/egress rules = deny all
354
.endSpec()
355
.build();
356
357
client.network().v1().networkPolicies()
358
.inNamespace("my-project")
359
.create(isolationPolicy);
360
361
// Allow ingress from specific project
362
NetworkPolicy allowFromProject = new NetworkPolicyBuilder()
363
.withNewMetadata()
364
.withName("allow-from-frontend")
365
.withNamespace("my-project")
366
.endMetadata()
367
.withNewSpec()
368
.withNewPodSelector()
369
.addToMatchLabels("app", "backend")
370
.endPodSelector()
371
.withPolicyTypes("Ingress")
372
.addNewIngress()
373
.addNewFrom()
374
.withNewNamespaceSelector()
375
.addToMatchLabels("name", "frontend-project")
376
.endNamespaceSelector()
377
.endFrom()
378
.endIngress()
379
.endSpec()
380
.build();
381
382
client.network().v1().networkPolicies()
383
.inNamespace("my-project")
384
.create(allowFromProject);
385
```
386
387
## Usage Examples
388
389
### Complete Project Setup Example
390
391
```java
392
import io.fabric8.openshift.client.OpenShiftClient;
393
import io.fabric8.kubernetes.api.model.*;
394
import io.fabric8.kubernetes.api.model.rbac.*;
395
396
public class ProjectManager {
397
private final OpenShiftClient client;
398
399
public ProjectManager(OpenShiftClient client) {
400
this.client = client;
401
}
402
403
public void setupCompleteProject(String projectName, String displayName,
404
String description, String adminUser,
405
List<String> developers, List<String> viewers) {
406
407
// 1. Create project with initial admin
408
System.out.println("Creating project: " + projectName);
409
Namespace project = client.projects()
410
.createProjectAndRoleBindings(projectName, description, displayName, adminUser);
411
412
// 2. Set up additional role bindings
413
setupProjectRoles(projectName, developers, viewers);
414
415
// 3. Create resource quota
416
setupResourceQuota(projectName);
417
418
// 4. Create network policies
419
setupNetworkPolicies(projectName);
420
421
// 5. Create default pull secret
422
setupPullSecrets(projectName);
423
424
System.out.println("Project setup completed: " + projectName);
425
}
426
427
private void setupProjectRoles(String projectName, List<String> developers,
428
List<String> viewers) {
429
// Add developers with edit role
430
if (!developers.isEmpty()) {
431
RoleBinding devBinding = new RoleBindingBuilder()
432
.withNewMetadata()
433
.withName("developers")
434
.withNamespace(projectName)
435
.endMetadata()
436
.withNewRoleRef()
437
.withApiGroup("rbac.authorization.k8s.io")
438
.withKind("ClusterRole")
439
.withName("edit")
440
.endRoleRef()
441
.build();
442
443
for (String dev : developers) {
444
devBinding.getSubjects().add(new SubjectBuilder()
445
.withKind("User")
446
.withName(dev)
447
.withApiGroup("rbac.authorization.k8s.io")
448
.build());
449
}
450
451
client.rbac().roleBindings()
452
.inNamespace(projectName)
453
.create(devBinding);
454
}
455
456
// Add viewers with view role
457
if (!viewers.isEmpty()) {
458
RoleBinding viewBinding = new RoleBindingBuilder()
459
.withNewMetadata()
460
.withName("viewers")
461
.withNamespace(projectName)
462
.endMetadata()
463
.withNewRoleRef()
464
.withApiGroup("rbac.authorization.k8s.io")
465
.withKind("ClusterRole")
466
.withName("view")
467
.endRoleRef()
468
.build();
469
470
for (String viewer : viewers) {
471
viewBinding.getSubjects().add(new SubjectBuilder()
472
.withKind("User")
473
.withName(viewer)
474
.withApiGroup("rbac.authorization.k8s.io")
475
.build());
476
}
477
478
client.rbac().roleBindings()
479
.inNamespace(projectName)
480
.create(viewBinding);
481
}
482
}
483
484
private void setupResourceQuota(String projectName) {
485
ResourceQuota quota = new ResourceQuotaBuilder()
486
.withNewMetadata()
487
.withName("compute-quota")
488
.withNamespace(projectName)
489
.endMetadata()
490
.withNewSpec()
491
.addToHard("requests.cpu", new Quantity("4"))
492
.addToHard("requests.memory", new Quantity("8Gi"))
493
.addToHard("limits.cpu", new Quantity("8"))
494
.addToHard("limits.memory", new Quantity("16Gi"))
495
.addToHard("persistentvolumeclaims", new Quantity("20"))
496
.addToHard("pods", new Quantity("50"))
497
.addToHard("services", new Quantity("20"))
498
.addToHard("secrets", new Quantity("50"))
499
.addToHard("configmaps", new Quantity("50"))
500
.endSpec()
501
.build();
502
503
client.resourceQuotas()
504
.inNamespace(projectName)
505
.create(quota);
506
}
507
508
private void setupNetworkPolicies(String projectName) {
509
// Allow ingress from OpenShift system namespaces
510
NetworkPolicy allowSystem = new NetworkPolicyBuilder()
511
.withNewMetadata()
512
.withName("allow-from-openshift")
513
.withNamespace(projectName)
514
.endMetadata()
515
.withNewSpec()
516
.withNewPodSelector() // All pods
517
.endPodSelector()
518
.withPolicyTypes("Ingress")
519
.addNewIngress()
520
.addNewFrom()
521
.withNewNamespaceSelector()
522
.addToMatchLabels("name", "openshift-ingress")
523
.endNamespaceSelector()
524
.endFrom()
525
.endIngress()
526
.addNewIngress()
527
.addNewFrom()
528
.withNewNamespaceSelector()
529
.addToMatchLabels("name", "openshift-monitoring")
530
.endNamespaceSelector()
531
.endFrom()
532
.endIngress()
533
.endSpec()
534
.build();
535
536
client.network().v1().networkPolicies()
537
.inNamespace(projectName)
538
.create(allowSystem);
539
}
540
541
private void setupPullSecrets(String projectName) {
542
// Link default pull secret to default service account
543
ServiceAccount defaultSA = client.serviceAccounts()
544
.inNamespace(projectName)
545
.withName("default")
546
.get();
547
548
if (defaultSA != null) {
549
client.serviceAccounts()
550
.inNamespace(projectName)
551
.withName("default")
552
.edit(sa -> new ServiceAccountBuilder(sa)
553
.addNewImagePullSecret()
554
.withName("default-dockercfg-secret")
555
.endImagePullSecret()
556
.build());
557
}
558
}
559
560
public void cleanupProject(String projectName) {
561
System.out.println("Cleaning up project: " + projectName);
562
563
// Get project first to ensure it exists
564
Namespace project = client.projects().withName(projectName).get();
565
if (project == null) {
566
System.out.println("Project not found: " + projectName);
567
return;
568
}
569
570
// Delete project (this cascades to all resources)
571
Boolean deleted = client.projects()
572
.withName(projectName)
573
.delete();
574
575
if (deleted) {
576
// Wait for project deletion
577
client.projects()
578
.withName(projectName)
579
.waitUntilCondition(Objects::isNull, 5, TimeUnit.MINUTES);
580
581
System.out.println("Project deleted: " + projectName);
582
} else {
583
System.err.println("Failed to delete project: " + projectName);
584
}
585
}
586
}
587
```
588
589
## Types
590
591
### ProjectOperation
592
593
```java { .api }
594
public interface ProjectOperation extends NonNamespaceOperation<Namespace, NamespaceList, Resource<Namespace>> {
595
596
/**
597
* Create a new project with role bindings for the specified user.
598
*
599
* @param name project name
600
* @param description project description
601
* @param displayName project display name
602
* @param adminUser user to grant admin access
603
* @return created Namespace (project)
604
*/
605
Namespace createProjectAndRoleBindings(String name, String description,
606
String displayName, String adminUser);
607
}
608
```
609
610
### ProjectRequestOperation
611
612
```java { .api }
613
public interface ProjectRequestOperation extends
614
InOutCreateable<ProjectRequest, ProjectRequest> {
615
// Inherits create methods for ProjectRequest objects
616
}
617
```
618
619
### ProjectRequest
620
621
```java { .api }
622
public class ProjectRequest implements HasMetadata {
623
public ObjectMeta getMetadata();
624
public String getDisplayName();
625
public String getDescription();
626
}
627
```
628
629
### Project-related Kubernetes Types
630
631
```java { .api }
632
// Projects are represented as Kubernetes Namespaces with additional annotations
633
public class Namespace implements HasMetadata {
634
public ObjectMeta getMetadata();
635
public NamespaceSpec getSpec();
636
public NamespaceStatus getStatus();
637
}
638
639
public class NamespaceSpec {
640
public List<String> getFinalizers();
641
}
642
643
public class NamespaceStatus {
644
public String getPhase(); // Active, Terminating
645
public List<NamespaceCondition> getConditions();
646
}
647
```