Closed pawelprazak closed 4 months ago
I was able to minify and reproduce the error in an integration test.
While reading the provider schema I've found this interesting info about stringData
being "special":
stringData allows specifying non-binary secret data in string form.
It is provided as a write-only input field for convenience.
All keys and values are merged into the data field on write,
overwriting any existing values. The stringData field is never
output when reading from the API.
While reading the implementation I've found the probable source of the error message, deep in the deserialization logic.
case resource.SecretSig:
value, ok := obj["value"]
if !ok {
return nil, fmt.Errorf("malformed RPC secret: missing value for %q", key)
}
return unmarshalSecretPropertyValue(value, opts), nil
IIUC Pulumi Outputs that are secrets are required to have the value on the wire level.
Interesting thing happened. After adding minified version of the Secret
from kubernetes provider:
test("#383 regression") {
given Context = DummyContext().unsafeRunSync()
val e = summon[Encoder[Output[Secret]]]
val (_, encoded) = e.encode(Secret("name", SecretArgs())).unsafeRunSync()
assertEqualsValue(encoded, Null)
}
object Regression383Test:
final case class Secret private (
urn: besom.types.Output[besom.types.URN],
id: besom.types.Output[besom.types.ResourceId],
data: besom.types.Output[Map[String, String]]
) extends besom.CustomResource
object Secret extends besom.ResourceCompanion[Secret]:
def apply(using ctx: besom.types.Context)(
name: besom.util.NonEmptyString,
args: SecretArgs = SecretArgs()
): besom.types.Output[Secret] =
ctx.readOrRegisterResource[Secret, SecretArgs](typeToken, name, args, besom.CustomResourceOptions())
private[besom] def typeToken: besom.types.ResourceType = "kubernetes:core/v1:Secret"
given resourceDecoder(using besom.types.Context): besom.types.ResourceDecoder[Secret] =
besom.internal.ResourceDecoder.derived[Secret]
given decoder(using besom.types.Context): besom.types.Decoder[Secret] =
besom.internal.Decoder.customResourceDecoder[Secret]
final case class SecretArgs private (
data: besom.types.Output[scala.Option[scala.Predef.Map[String, String]]]
)
object SecretArgs:
def apply(
data: besom.types.Input.Optional[Map[String, besom.types.Input[String]]] = None
)(using besom.types.Context): SecretArgs =
new SecretArgs(
data = data.asOptionOutput(isSecret = true)
)
given encoder(using besom.types.Context): besom.types.Encoder[SecretArgs] =
besom.internal.Encoder.derived[SecretArgs]
given argsEncoder(using besom.types.Context): besom.types.ArgsEncoder[SecretArgs] =
besom.internal.ArgsEncoder.derived[SecretArgs]
The test hangs at this line:
Given this is unsafeRunSync()
I assume it is separate issue.
This exception was printed to the console:
java.lang.NoSuchMethodError: 'com.google.protobuf.struct.Value$Kind$StructValue com.google.protobuf.struct.Value$Kind$StructValue$.unapply(com.google.protobuf.struct.Value$Kind$StructValue)'
at besom.internal.PropertiesSerializer$.detectUnknowns(PropertiesSerializer.scala:29)
at besom.internal.PropertiesSerializer$.serializeFilteredProperties$$anonfun$1(PropertiesSerializer.scala:23)
at besom.internal.Result.map$$anonfun$1(Result.scala:201)
at besom.internal.Result.flatMap$$anonfun$1(Result.scala:164)
at besom.internal.Result.runM$$anonfun$7(Result.scala:269)
at besom.internal.Runtime.flatMapBothM$$anonfun$1$$anonfun$1(Result.scala:118)
at besom.internal.FutureRuntime.flatMapBoth$$anonfun$1(Result.scala:372)
at scala.concurrent.impl.Promise$Transformation.run$$$capture(Promise.scala:477)
at scala.concurrent.impl.Promise$Transformation.run(Promise.scala)
at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1423)
at java.base/java.util.concurrent.ForkJoinTask.doExec$$$capture(ForkJoinTask.java:387)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1312)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1843)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1808)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:188)
It's test scope, right? It probably uses global EC and that's why it hangs.
On Mon 12. Feb 2024 at 10:23, Paweł Prażak @.***> wrote:
Interesting thing happened. After adding minified version of the Secret from kubernetes provider:
test("#383 regression") { given Context = DummyContext().unsafeRunSync() val e = summon[Encoder[Output[Secret]]]
val (_, encoded) = e.encode(Secret("name", SecretArgs())).unsafeRunSync() assertEqualsValue(encoded, Null)
} object Regression383Test: final case class Secret private ( urn: besom.types.Output[besom.types.URN], id: besom.types.Output[besom.types.ResourceId], data: besom.types.Output[Map[String, String]] ) extends besom.CustomResource object Secret extends besom.ResourceCompanion[Secret]: def apply(using ctx: besom.types.Context)( name: besom.util.NonEmptyString, args: SecretArgs = SecretArgs() ): besom.types.Output[Secret] = ctx.readOrRegisterResource[Secret, SecretArgs](typeToken, name, args, besom.CustomResourceOptions())
private[besom] def typeToken: besom.types.ResourceType = "kubernetes:core/v1:Secret" given resourceDecoder(using besom.types.Context): besom.types.ResourceDecoder[Secret] = besom.internal.ResourceDecoder.derived[Secret] given decoder(using besom.types.Context): besom.types.Decoder[Secret] = besom.internal.Decoder.customResourceDecoder[Secret]
final case class SecretArgs private ( data: besom.types.Output[scala.Option[scala.Predef.Map[String, String]]] )
object SecretArgs: def apply( data: besom.types.Input.Optional[Map[String, besom.types.Input[String]]] = None )(using besom.types.Context): SecretArgs = new SecretArgs( data = data.asOptionOutput(isSecret = true) )
given encoder(using besom.types.Context): besom.types.Encoder[SecretArgs] = besom.internal.Encoder.derived[SecretArgs] given argsEncoder(using besom.types.Context): besom.types.ArgsEncoder[SecretArgs] = besom.internal.ArgsEncoder.derived[SecretArgs]
The test hangs at this line: Screenshot.2024-02-12.at.10.20.51.png (view on web) https://github.com/VirtusLab/besom/assets/48874/eb0d2ed3-f84c-40ce-84bd-cd66f6f46d51
Screenshot.2024-02-12.at.10.22.07.png (view on web) https://github.com/VirtusLab/besom/assets/48874/066b7957-d305-4318-a42e-54f5079056af
After this exception was printed:
java.lang.NoSuchMethodError: 'com.google.protobuf.struct.Value$Kind$StructValue com.google.protobuf.struct.Value$Kind$StructValue$.unapply(com.google.protobuf.struct.Value$Kind$StructValue)' at besom.internal.PropertiesSerializer$.detectUnknowns(PropertiesSerializer.scala:29) at besom.internal.PropertiesSerializer$.serializeFilteredProperties$$anonfun$1(PropertiesSerializer.scala:23) at besom.internal.Result.map$$anonfun$1(Result.scala:201) at besom.internal.Result.flatMap$$anonfun$1(Result.scala:164) at besom.internal.Result.runM$$anonfun$7(Result.scala:269) at besom.internal.Runtime.flatMapBothM$$anonfun$1$$anonfun$1(Result.scala:118) at besom.internal.FutureRuntime.flatMapBoth$$anonfun$1(Result.scala:372) at scala.concurrent.impl.Promise$Transformation.run$$$capture(Promise.scala:477) at scala.concurrent.impl.Promise$Transformation.run(Promise.scala) at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1423) at java.base/java.util.concurrent.ForkJoinTask.doExec$$$capture(ForkJoinTask.java:387) at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java) at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1312) at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1843) at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1808) at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:188)
Given this is unsafeRunSync() I assume it is separate issue.
— Reply to this email directly, view it on GitHub https://github.com/VirtusLab/besom/issues/383#issuecomment-1938300530, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACBVNUT72JK42EWYWN2OLMDYTHNSZAVCNFSM6AAAAABDCZBAUKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSMZYGMYDANJTGA . You are receiving this because you are subscribed to this thread.Message ID: @.***>
It's test scope, right? It probably uses global EC and that's why it hangs.
yes it appears so, but I have a strong suspicion that the stack trace is related, because the log trace abruptly ends like this:
2024.02.13 09:19:35:213 scala-execution-context-global-46 [resource: test-secret1[kubernetes:core/v1:Secret]] TRACE besom.internal.ResourceOps.executeRegisterResourceRequest:491
RegisterResourceRequest for test-secret1[kubernetes:core/v1:Secret]: RegisterResourceRequest(
type = "kubernetes:core/v1:Secret",
name = "test-secret1",
parent = "urn:pulumi:tests-kubernetes-provider-should-work-with-sec5c920e6c2daa3ac41edf1c047b3027dba3196925::kubernetes-secrets::pulumi:pulumi:Stack::kubernetes-secrets-tests-kubernetes-provider-should-work-with-sec5c920e6c2daa3ac41edf1c047b3027dba3196925",
custom = true,
object = Some(
value = Struct(
fields = HashMap(
"data" -> Value(
kind = StructValue(
value = Struct(
fields = Map(
"4dabf18193072939515e22adb298388d" -> Value(
kind = StringValue(value = "1b47061264138c4ac30d75fd1eb44270"),
unknownFields = UnknownFieldSet(fields = Map())
),
"value" -> Value(kind = NullValue(value = NULL_VALUE), unknownFields = UnknownFieldSet(fields = Map()))
),
unknownFields = UnknownFieldSet(fields = Map())
)
),
unknownFields = UnknownFieldSet(fields = Map())
),
"metadata" -> Value(
kind = StructValue(
value = Struct(
fields = Map(
"name" -> Value(
kind = StringValue(value = "test-secret1"),
unknownFields = UnknownFieldSet(fields = Map())
)
),
unknownFields = UnknownFieldSet(fields = Map())
)
),
unknownFields = UnknownFieldSet(fields = Map())
),
"stringData" -> Value(
kind = StructValue(
value = Struct(
fields = Map(
"4dabf18193072939515e22adb298388d" -> Value(
kind = StringValue(value = "1b47061264138c4ac30d75fd1eb44270"),
unknownFields = Unknown
I've compared logs from the engine between besom and TS:
TS:
I0213 13:12:35.720820 16869 rpc.go:292] Unmarshaling property for RPC[ResourceMonitor.RegisterResource(kubernetes:core/v1:Secret,secret1)]: apiVersion={v1}
I0213 13:12:35.720852 16869 rpc.go:292] Unmarshaling property for RPC[ResourceMonitor.RegisterResource(kubernetes:core/v1:Secret,secret1)]: kind={Secret}
I0213 13:12:35.720870 16869 rpc.go:292] Unmarshaling property for RPC[ResourceMonitor.RegisterResource(kubernetes:core/v1:Secret,secret1)]: 4dabf18193072939515e22adb298388d={1b47061264138c4ac30d75fd1eb44270}
I0213 13:12:35.720883 16869 rpc.go:292] Unmarshaling property for RPC[ResourceMonitor.RegisterResource(kubernetes:core/v1:Secret,secret1)]: password={test-password}
I0213 13:12:35.720893 16869 rpc.go:292] Unmarshaling property for RPC[ResourceMonitor.RegisterResource(kubernetes:core/v1:Secret,secret1)]: username={test-user}
I0213 13:12:35.721016 16869 rpc.go:292] Unmarshaling property for RPC[ResourceMonitor.RegisterResource(kubernetes:core/v1:Secret,secret1)]: value={map[password:{test-password} username:{test-user}]}
I0213 13:12:35.721050 16869 rpc.go:292] Unmarshaling property for RPC[ResourceMonitor.RegisterResource(kubernetes:core/v1:Secret,secret1)]: stringData={&{{map[password:{test-password} username:{test-user}]}}}
besom:
I0213 13:15:24.975319 17339 rpc.go:292] Unmarshaling property for RPC[ResourceMonitor.RegisterResource(kubernetes:core/v1:Secret,test-secret1)]: apiVersion={v1}
I0213 13:15:24.975332 17339 rpc.go:292] Unmarshaling property for RPC[ResourceMonitor.RegisterResource(kubernetes:core/v1:Secret,test-secret1)]: 4dabf18193072939515e22adb298388d={1b47061264138c4ac30d75fd1eb44270}
I0213 13:15:24.975337 17339 rpc.go:292] Unmarshaling property for RPC[ResourceMonitor.RegisterResource(kubernetes:core/v1:Secret,test-secret1)]: value={<nil>}
I0213 13:15:24.975351 17339 rpc.go:292] Unmarshaling property for RPC[ResourceMonitor.RegisterResource(kubernetes:core/v1:Secret,test-secret1)]: data={&{{<nil>}}}
I0213 13:15:24.975357 17339 rpc.go:292] Unmarshaling property for RPC[ResourceMonitor.RegisterResource(kubernetes:core/v1:Secret,test-secret1)]: kind={Secret}
I0213 13:15:24.975362 17339 rpc.go:292] Unmarshaling property for RPC[ResourceMonitor.RegisterResource(kubernetes:core/v1:Secret,test-secret1)]: name={test-secret1}
I0213 13:15:24.975383 17339 rpc.go:292] Unmarshaling property for RPC[ResourceMonitor.RegisterResource(kubernetes:core/v1:Secret,test-secret1)]: metadata={map[name:{test-secret1}]}
I0213 13:15:24.975399 17339 rpc.go:292] Unmarshaling property for RPC[ResourceMonitor.RegisterResource(kubernetes:core/v1:Secret,test-secret1)]: 4dabf18193072939515e22adb298388d={1b47061264138c4ac30d75fd1eb44270}
I0213 13:15:24.975420 17339 rpc.go:292] Unmarshaling property for RPC[ResourceMonitor.RegisterResource(kubernetes:core/v1:Secret,test-secret1)]: password={test-password}
I0213 13:15:24.975432 17339 rpc.go:292] Unmarshaling property for RPC[ResourceMonitor.RegisterResource(kubernetes:core/v1:Secret,test-secret1)]: username={test-user}
I0213 13:15:24.975443 17339 rpc.go:292] Unmarshaling property for RPC[ResourceMonitor.RegisterResource(kubernetes:core/v1:Secret,test-secret1)]: value={map[password:{test-password} username:{test-user}]}
I0213 13:15:24.975481 17339 rpc.go:292] Unmarshaling property for RPC[ResourceMonitor.RegisterResource(kubernetes:core/v1:Secret,test-secret1)]: stringData={&{{map[password:{test-password} username:{test-user}]}}}
We've mimicked the observer behavior of TS implementation, and added logic to the serializer to skip outputs that are both secret and null.
Workaround: define both
stringData
anddata
until this problem is solved.