or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

api-groups.mdclient-configuration.mdcore-resources.mdcustom-resources.mdexception-handling.mdindex.mdpod-operations.mdutilities.mdwatch-informers.md

custom-resources.mddocs/

0

# Custom Resources

1

2

The Fabric8 Kubernetes Client provides comprehensive support for Custom Resource Definitions (CRDs) and custom resources. This includes type-safe operations on custom resources, dynamic resource handling for unknown types, and utilities for working with CRDs.

3

4

## Custom Resource Support

5

6

### CustomResource Base Class

7

8

Base class for creating type-safe custom resource implementations.

9

10

```java { .api }

11

public abstract class CustomResource<T, S> implements HasMetadata {

12

// Spec and Status management

13

public T getSpec();

14

public void setSpec(T spec);

15

public S getStatus();

16

public void setStatus(S status);

17

18

// Metadata implementation from HasMetadata

19

public ObjectMeta getMetadata();

20

public void setMetadata(ObjectMeta metadata);

21

public String getKind();

22

public void setKind(String kind);

23

public String getApiVersion();

24

public void setApiVersion(String apiVersion);

25

}

26

```

27

28

### Typed Custom Resource Operations

29

30

Operations on strongly-typed custom resources using the generic resources method.

31

32

```java { .api }

33

public interface KubernetesClient {

34

<T extends HasMetadata> MixedOperation<T, KubernetesResourceList<T>, Resource<T>>

35

resources(Class<T> resourceType);

36

37

<T extends HasMetadata> MixedOperation<T, KubernetesResourceList<T>, Resource<T>>

38

resources(Class<T> resourceType, Class<? extends KubernetesResourceList<T>> listClass);

39

}

40

```

41

42

### Generic Resource Operations

43

44

Operations on custom resources using GenericKubernetesResource for dynamic handling.

45

46

```java { .api }

47

public interface KubernetesClient {

48

MixedOperation<GenericKubernetesResource, GenericKubernetesResourceList, Resource<GenericKubernetesResource>>

49

genericKubernetesResources(String apiVersion, String kind);

50

51

MixedOperation<GenericKubernetesResource, GenericKubernetesResourceList, Resource<GenericKubernetesResource>>

52

genericKubernetesResources(ResourceDefinitionContext context);

53

}

54

```

55

56

### ResourceDefinitionContext

57

58

Context information for custom resource definitions.

59

60

```java { .api }

61

public class ResourceDefinitionContext {

62

// Factory methods

63

public static ResourceDefinitionContext fromResourceType(Class<? extends HasMetadata> resourceType);

64

public static ResourceDefinitionContext fromCrd(CustomResourceDefinition crd);

65

66

// Properties

67

public String getGroup();

68

public String getVersion();

69

public String getKind();

70

public String getPlural();

71

public String getSingular();

72

public boolean isNamespaceScoped();

73

74

// Builder methods

75

public static ResourceDefinitionContextBuilder builder();

76

}

77

```

78

79

## Custom Resource Definition Operations

80

81

### CRD Management

82

83

Operations for managing Custom Resource Definitions.

84

85

```java { .api }

86

public interface ApiextensionsAPIGroupDSL {

87

// V1 API (preferred)

88

V1ApiextensionsAPIGroupDSL v1();

89

90

// Default methods (v1)

91

NonNamespaceOperation<CustomResourceDefinition, CustomResourceDefinitionList, Resource<CustomResourceDefinition>> customResourceDefinitions();

92

}

93

94

public interface V1ApiextensionsAPIGroupDSL {

95

NonNamespaceOperation<CustomResourceDefinition, CustomResourceDefinitionList, Resource<CustomResourceDefinition>> customResourceDefinitions();

96

}

97

98

// Access via client

99

public interface KubernetesClient {

100

ApiextensionsAPIGroupDSL apiextensions();

101

}

102

```

103

104

## Usage Examples

105

106

### Defining a Custom Resource Class

107

108

```java

109

// Define the spec class

110

public class DatabaseSpec {

111

private String version;

112

private int replicas;

113

private String storageSize;

114

115

// Getters and setters

116

public String getVersion() { return version; }

117

public void setVersion(String version) { this.version = version; }

118

119

public int getReplicas() { return replicas; }

120

public void setReplicas(int replicas) { this.replicas = replicas; }

121

122

public String getStorageSize() { return storageSize; }

123

public void setStorageSize(String storageSize) { this.storageSize = storageSize; }

124

}

125

126

// Define the status class

127

public class DatabaseStatus {

128

private String phase;

129

private String message;

130

private List<String> conditions;

131

132

// Getters and setters

133

public String getPhase() { return phase; }

134

public void setPhase(String phase) { this.phase = phase; }

135

136

public String getMessage() { return message; }

137

public void setMessage(String message) { this.message = message; }

138

139

public List<String> getConditions() { return conditions; }

140

public void setConditions(List<String> conditions) { this.conditions = conditions; }

141

}

142

143

// Define the custom resource class

144

@Group("example.com")

145

@Version("v1")

146

@Kind("Database")

147

@Plural("databases")

148

@Singular("database")

149

public class Database extends CustomResource<DatabaseSpec, DatabaseStatus> {

150

// The CustomResource base class provides all necessary methods

151

}

152

```

153

154

### Creating a Custom Resource Definition

155

156

```java

157

// Create CRD for the Database custom resource

158

CustomResourceDefinition crd = client.apiextensions().v1().customResourceDefinitions()

159

.create(new CustomResourceDefinitionBuilder()

160

.withNewMetadata()

161

.withName("databases.example.com")

162

.endMetadata()

163

.withNewSpec()

164

.withGroup("example.com")

165

.withScope("Namespaced")

166

.addNewVersion()

167

.withName("v1")

168

.withServed(true)

169

.withStorage(true)

170

.withNewSchema()

171

.withNewOpenAPIV3Schema()

172

.withType("object")

173

.addToProperties("spec", new JSONSchemaPropsBuilder()

174

.withType("object")

175

.addToProperties("version", new JSONSchemaPropsBuilder()

176

.withType("string")

177

.build())

178

.addToProperties("replicas", new JSONSchemaPropsBuilder()

179

.withType("integer")

180

.withMinimum(1.0)

181

.build())

182

.addToProperties("storageSize", new JSONSchemaPropsBuilder()

183

.withType("string")

184

.build())

185

.build())

186

.addToProperties("status", new JSONSchemaPropsBuilder()

187

.withType("object")

188

.addToProperties("phase", new JSONSchemaPropsBuilder()

189

.withType("string")

190

.build())

191

.addToProperties("message", new JSONSchemaPropsBuilder()

192

.withType("string")

193

.build())

194

.build())

195

.build()

196

.endSchema()

197

.endVersion()

198

.withNewNames()

199

.withKind("Database")

200

.withPlural("databases")

201

.withSingular("database")

202

.endNames()

203

.endSpec()

204

.build());

205

206

System.out.println("Created CRD: " + crd.getMetadata().getName());

207

```

208

209

### Working with Typed Custom Resources

210

211

```java

212

// Create a Database custom resource instance

213

Database database = new Database();

214

database.setMetadata(new ObjectMetaBuilder()

215

.withName("my-database")

216

.withNamespace("production")

217

.build());

218

219

DatabaseSpec spec = new DatabaseSpec();

220

spec.setVersion("13.4");

221

spec.setReplicas(3);

222

spec.setStorageSize("100Gi");

223

database.setSpec(spec);

224

225

// Create the custom resource

226

Database created = client.resources(Database.class).create(database);

227

System.out.println("Created database: " + created.getMetadata().getName());

228

229

// List all Database resources

230

KubernetesResourceList<Database> databases = client.resources(Database.class).list();

231

for (Database db : databases.getItems()) {

232

System.out.println("Database: " + db.getMetadata().getName() +

233

" version: " + db.getSpec().getVersion());

234

}

235

236

// Update custom resource

237

Database updated = client.resources(Database.class)

238

.withName("my-database")

239

.edit(db -> {

240

db.getSpec().setReplicas(5);

241

return db;

242

});

243

244

// Update status subresource

245

client.resources(Database.class)

246

.withName("my-database")

247

.editStatus(db -> {

248

DatabaseStatus status = new DatabaseStatus();

249

status.setPhase("Running");

250

status.setMessage("Database is healthy");

251

db.setStatus(status);

252

return db;

253

});

254

255

// Watch for changes

256

Watch watch = client.resources(Database.class).watch(new Watcher<Database>() {

257

@Override

258

public void eventReceived(Action action, Database database) {

259

System.out.println(action + ": " + database.getMetadata().getName());

260

if (database.getStatus() != null) {

261

System.out.println("Status: " + database.getStatus().getPhase());

262

}

263

}

264

265

@Override

266

public void onClose(WatcherException cause) {

267

System.out.println("Watch closed: " + cause);

268

}

269

});

270

```

271

272

### Working with Generic Resources

273

274

When you don't have a typed class or need to work with arbitrary custom resources:

275

276

```java

277

// Using apiVersion and kind

278

MixedOperation<GenericKubernetesResource, GenericKubernetesResourceList, Resource<GenericKubernetesResource>>

279

genericOp = client.genericKubernetesResources("example.com/v1", "Database");

280

281

// Create a generic custom resource

282

GenericKubernetesResource genericDatabase = new GenericKubernetesResource();

283

genericDatabase.setApiVersion("example.com/v1");

284

genericDatabase.setKind("Database");

285

genericDatabase.setMetadata(new ObjectMetaBuilder()

286

.withName("generic-database")

287

.withNamespace("default")

288

.build());

289

290

// Set spec using the additional properties map

291

Map<String, Object> spec = new HashMap<>();

292

spec.put("version", "14.1");

293

spec.put("replicas", 2);

294

spec.put("storageSize", "50Gi");

295

genericDatabase.setAdditionalProperty("spec", spec);

296

297

// Create the resource

298

GenericKubernetesResource created = genericOp.create(genericDatabase);

299

300

// Access spec properties

301

Map<String, Object> createdSpec = (Map<String, Object>) created.getAdditionalProperties().get("spec");

302

String version = (String) createdSpec.get("version");

303

Integer replicas = (Integer) createdSpec.get("replicas");

304

305

System.out.println("Created database version: " + version + " with " + replicas + " replicas");

306

307

// List generic resources

308

GenericKubernetesResourceList list = genericOp.list();

309

for (GenericKubernetesResource resource : list.getItems()) {

310

System.out.println("Found resource: " + resource.getMetadata().getName());

311

}

312

```

313

314

### Using ResourceDefinitionContext

315

316

For more explicit resource definition:

317

318

```java

319

// Create ResourceDefinitionContext

320

ResourceDefinitionContext context = new ResourceDefinitionContextBuilder()

321

.withGroup("example.com")

322

.withVersion("v1")

323

.withKind("Database")

324

.withPlural("databases")

325

.withNamespaceScoped(true)

326

.build();

327

328

// Use with generic resources

329

MixedOperation<GenericKubernetesResource, GenericKubernetesResourceList, Resource<GenericKubernetesResource>>

330

contextOp = client.genericKubernetesResources(context);

331

332

// All operations work the same as with apiVersion/kind approach

333

GenericKubernetesResourceList databases = contextOp.inNamespace("production").list();

334

```

335

336

### Custom Resource from CRD

337

338

Create ResourceDefinitionContext from an existing CRD:

339

340

```java

341

// Get existing CRD

342

CustomResourceDefinition crd = client.apiextensions().v1().customResourceDefinitions()

343

.withName("databases.example.com")

344

.get();

345

346

if (crd != null) {

347

// Create context from CRD

348

ResourceDefinitionContext context = ResourceDefinitionContext.fromCrd(crd);

349

350

// Use for operations

351

MixedOperation<GenericKubernetesResource, GenericKubernetesResourceList, Resource<GenericKubernetesResource>>

352

crdOp = client.genericKubernetesResources(context);

353

354

GenericKubernetesResourceList resources = crdOp.list();

355

System.out.println("Found " + resources.getItems().size() + " custom resources");

356

}

357

```

358

359

### Custom Resource Informers

360

361

Custom resources work with the informer framework:

362

363

```java

364

// Create informer for typed custom resource

365

SharedIndexInformer<Database> informer = client.informers()

366

.sharedIndexInformerForCustomResource(Database.class, 30 * 1000);

367

368

informer.addEventHandler(new ResourceEventHandler<Database>() {

369

@Override

370

public void onAdd(Database database) {

371

System.out.println("Database added: " + database.getMetadata().getName());

372

}

373

374

@Override

375

public void onUpdate(Database oldDatabase, Database newDatabase) {

376

System.out.println("Database updated: " + newDatabase.getMetadata().getName());

377

}

378

379

@Override

380

public void onDelete(Database database, boolean deletedFinalStateUnknown) {

381

System.out.println("Database deleted: " + database.getMetadata().getName());

382

}

383

});

384

385

// Start the informer

386

client.informers().startAllRegisteredInformers();

387

388

// Get cached resources

389

List<Database> cachedDatabases = informer.getIndexer().list();

390

```

391

392

## Error Handling

393

394

Custom resource operations can encounter specific errors:

395

396

```java

397

try {

398

Database db = client.resources(Database.class).withName("non-existent").get();

399

} catch (KubernetesClientException e) {

400

if (e.getCode() == 404) {

401

System.out.println("Custom resource not found");

402

} else if (e.getCode() == 400) {

403

System.out.println("Invalid custom resource definition: " + e.getMessage());

404

}

405

}

406

407

// Check if CRD exists before using custom resources

408

CustomResourceDefinition crd = client.apiextensions().v1().customResourceDefinitions()

409

.withName("databases.example.com")

410

.get();

411

412

if (crd == null) {

413

System.out.println("CRD not found - cannot work with Database resources");

414

} else {

415

// Safe to use Database resources

416

KubernetesResourceList<Database> databases = client.resources(Database.class).list();

417

}

418

```