Skip to content

Commit

Permalink
patch resources
Browse files Browse the repository at this point in the history
  • Loading branch information
EronWright committed May 24, 2024
1 parent 4e4e91d commit 417f39d
Show file tree
Hide file tree
Showing 12 changed files with 485 additions and 539 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,22 @@
package com.pulumi.kubernetes.apiextensions;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.annotation.Nullable;

import com.pulumi.core.Either;
import com.pulumi.core.Output;
import com.pulumi.core.annotations.Export;
import com.pulumi.core.annotations.Import;
import com.pulumi.core.annotations.ResourceType;
import com.pulumi.core.internal.Codegen;
import com.pulumi.core.internal.Internal;
import com.pulumi.core.internal.OutputInternal;
import com.pulumi.core.internal.annotations.ImportMetadata;
import com.pulumi.kubernetes.Utilities;
import com.pulumi.kubernetes.meta.v1.outputs.ObjectMeta;
import com.pulumi.resources.ResourceArgs;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.implementation.FieldAccessor;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.implementation.MethodCall;

/**
* CustomResource represents an instance of a CustomResourceDefinition (CRD). For example, the
* CoreOS Prometheus operator exposes a CRD `monitoring.coreos.com/ServiceMonitor`; to
Expand Down Expand Up @@ -135,16 +119,6 @@ private static String getOutputValue(OutputInternal<String> o) {
}
}

private static class Field {
public Optional<?> value;
public Either<Annotation,AnnotationDescription> importAnnotation;

public Field(Optional<?> value, Either<Annotation,AnnotationDescription> importAnnotation) {
this.value = value;
this.importAnnotation = importAnnotation;
}
}

private static ResourceArgs makeArgs(@Nullable CustomResourceArgsBase args) {
if (args == null) {
return null;
Expand All @@ -153,53 +127,7 @@ private static ResourceArgs makeArgs(@Nullable CustomResourceArgsBase args) {
// optimization: if there are no "other" fields, we can just return the args as-is.
return args;
}

// collect the input properties from the annotated fields of the user-supplied args,
// plus the dynamic input properties within otherFields.
var importFields =
ImportMetadata.of(args.getClass()).values().stream()
.map(info -> new Field(info.getFieldOutput(args), Either.ofLeft(info.getAnnotation())));
var otherFields =
args.otherFields().orElseGet(Map::of).entrySet().stream()
.map(entry -> new Field(Optional.ofNullable(entry.getValue()), Either.ofRight(
AnnotationDescription.Builder.ofType(Import.class).define("name", entry.getKey()).build())));
List<Field> fields =
Stream.concat(importFields, otherFields)
.collect(Collectors.toList());

try {
// define a dynamic subclass of ResourceArgs with a field for each input property
// and a constructor that takes the property values and assigns them to the fields.
var t = new ByteBuddy().subclass(ResourceArgs.class);
Implementation.Composable c = MethodCall.invoke(ResourceArgs.class.getConstructor());

var paramTypes = new ArrayList<Class<?>>();
var paramValues = new ArrayList<Object>();

for (var arg : fields) {
// define a field of type Output with @Import(name="foo")
var fieldName = String.format("f%d", paramTypes.size());
var f = t.defineField(fieldName, Output.class, Modifier.PUBLIC);
t = arg.importAnnotation.either(a -> f.annotateField(a), ad -> f.annotateField(ad));

// bind the field to the corresponding constructor parameter
c = c.andThen(FieldAccessor.ofField(fieldName).setsArgumentAt(paramTypes.size()));

paramTypes.add(Output.class);
paramValues.add(arg.value.map(v -> v instanceof Output ? v : Output.ofNullable(v)).orElse(null));
}

return (ResourceArgs) t
.defineConstructor(Modifier.PUBLIC).withParameters(paramTypes).intercept(c)
.make()
.load(CustomResource.class.getClassLoader())
.getLoaded().getConstructors()[0]
.newInstance(paramValues.toArray());

} catch (NoSuchMethodException | InstantiationException | IllegalAccessException
| InvocationTargetException e) {
throw new RuntimeException(e);
}
return Util.generateResourceArgs(args, args.otherFields().get());
}

private static com.pulumi.resources.CustomResourceOptions makeResourceOptions(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// *** WARNING: this file was generated by pulumi-java-gen. ***
// *** Do not edit by hand unless you're certain you know what you are doing! ***

package com.pulumi.kubernetes.apiextensions;

import java.util.Optional;
import java.util.concurrent.ExecutionException;

import javax.annotation.Nullable;

import com.pulumi.core.Output;
import com.pulumi.core.annotations.Export;
import com.pulumi.core.annotations.ResourceType;
import com.pulumi.core.internal.Codegen;
import com.pulumi.core.internal.Internal;
import com.pulumi.core.internal.OutputInternal;
import com.pulumi.kubernetes.Utilities;
import com.pulumi.kubernetes.meta.v1.outputs.ObjectMetaPatch;
import com.pulumi.resources.ResourceArgs;

/**
* Patch resources are used to modify existing Kubernetes resources by using
* Server-Side Apply updates. The name of the resource must be specified, but all other properties are optional. More than
* one patch may be applied to the same resource, and a random FieldManager name will be used for each Patch resource.
* Conflicts will result in an error by default, but can be forced using the &#34;pulumi.com/patchForce&#34; annotation. See the
* [Server-Side Apply Docs](https://www.pulumi.com/registry/packages/kubernetes/how-to-guides/managing-resources-with-server-side-apply/) for
* additional information about using Server-Side Apply to manage Kubernetes resources with Pulumi.
*
* CustomResourcePatch represents an instance of a CustomResourceDefinition (CRD). For example, the
* CoreOS Prometheus operator exposes a CRD `monitoring.coreos.com/ServiceMonitor`; to
* instantiate this as a Pulumi resource, one could call `new CustomResourcePatch`, passing the
* `ServiceMonitor` resource definition as an argument.
*/
@ResourceType(type="kubernetes:apiextensions:CustomResourcePatch")
public class CustomResourcePatch extends com.pulumi.resources.CustomResource {
/**
* APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
*
*/
@Export(name="apiVersion", refs={String.class}, tree="[0]")
private Output</* @Nullable */ String> apiVersion;

/**
* @return APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
*
*/
public Output<Optional<String>> apiVersion() {
return Codegen.optional(this.apiVersion);
}

/**
* Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
*
*/
@Export(name="kind", refs={String.class}, tree="[0]")
private Output</* @Nullable */ String> kind;

/**
* @return Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
*
*/
public Output<Optional<String>> kind() {
return Codegen.optional(this.kind);
}
/**
* Standard object&#39;s metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
*
*/
@Export(name="metadata", refs={ObjectMetaPatch.class}, tree="[0]")
private Output</* @Nullable */ ObjectMetaPatch> metadata;

/**
* @return Standard object&#39;s metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
*
*/
public Output<Optional<ObjectMetaPatch>> metadata() {
return Codegen.optional(this.metadata);
}

/**
*
* @param name The _unique_ name of the resulting resource.
*/
public CustomResourcePatch(String name) {
this(name, CustomResourcePatchArgs.Empty);
}

/**
*
* @param name The _unique_ name of the resulting resource.
* @param args The arguments to use to populate this resource's properties.
*/
public CustomResourcePatch(String name, @Nullable CustomResourcePatchArgsBase args) {
this(name, args, null);
}

/**
*
* @param name The _unique_ name of the resulting resource.
* @param args The arguments to use to populate this resource's properties.
* @param options A bag of options that control this resource's behavior.
*/
public CustomResourcePatch(String name, @Nullable CustomResourcePatchArgsBase args, @Nullable com.pulumi.resources.CustomResourceOptions options) {
super(makeType(args), name, makeArgs(args), makeResourceOptions(options, Codegen.empty()));
}

private static String makeType(@Nullable CustomResourcePatchArgsBase args) {
String apiVersion = args.apiVersion().map(Internal::of).map(CustomResourcePatch::getOutputValue).orElse("");
String kind = args.kind().map(Internal::of).map(CustomResourcePatch::getOutputValue).orElse("");
return String.format("kubernetes:%s:%sPatch", apiVersion, kind);
}

private static String getOutputValue(OutputInternal<String> o) {
try {
return o.getValueOrDefault("").get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}

private static ResourceArgs makeArgs(@Nullable CustomResourcePatchArgsBase args) {
if (args == null) {
return null;
}
if (args.otherFields().isEmpty() || args.otherFields().get().isEmpty()) {
// optimization: if there are no "other" fields, we can just use the args as-is.
// Otherwise we generate a subclass of ResourceArgs that includes the "other" fields.
return args;
}
return Util.generateResourceArgs(args, args.otherFields().get());
}

private static com.pulumi.resources.CustomResourceOptions makeResourceOptions(
@Nullable com.pulumi.resources.CustomResourceOptions options, @Nullable Output<String> id) {
var defaultOptions = com.pulumi.resources.CustomResourceOptions.builder()
.version(Utilities.getVersion())
.build();
return com.pulumi.resources.CustomResourceOptions.merge(defaultOptions, options, id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// *** WARNING: this file was generated by pulumi-java-gen. ***
// *** Do not edit by hand unless you're certain you know what you are doing! ***

package com.pulumi.kubernetes.apiextensions;

/**
* The set of arguments for constructing a CustomResourcePatch resource.
*
* NOTE: This type is fairly loose, since other than `apiVersion` and `kind`,
* there are no fields required across all CRDs. Use otherFields(...) to specify
* additional fields.
*/
public final class CustomResourcePatchArgs extends CustomResourcePatchArgsBase {

public static final CustomResourcePatchArgs Empty = new CustomResourcePatchArgs();

public static Builder builder() {
return new Builder();
}

public static Builder builder(CustomResourcePatchArgs defaults) {
return new Builder(defaults);
}

public static final class Builder extends CustomResourcePatchArgsBase.Builder<CustomResourcePatchArgs, Builder> {
public Builder() {
super(new CustomResourcePatchArgs());
}

public Builder(CustomResourcePatchArgs defaults) {
super(new CustomResourcePatchArgs(), defaults);
}
}
}
Loading

0 comments on commit 417f39d

Please sign in to comment.