or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

api-group-operations.mdauthorization-reviews.mdbuild-operations.mdclient-configuration.mddeployment-operations.mdimage-operations.mdindex.mdnetwork-operations.mdproject-operations.mdtemplate-operations.mduser-security.md

project-operations.mddocs/

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

```