I have a basic Pulumi build for keycloak where I set up a realm, create a scope, create a client, and update teh scopes for my client.
class RealmBuild : Stack
{
public RealmBuild()
{
var realm = new Realm("ExampleRealm-realm", new RealmArgs
{
RealmName = "ExampleRealm"
});
var recipemanagementScope = ScopeFactory.CreateScope(realm.Id, "recipe_management");
var recipeManagementPostmanMachineClient = ClientFactory.CreateClientCredentialsFlowClient(realm.Id,
"recipe_management.postman.machine",
"974d6f71-d41b-4601-9a7a-a33084484682",
"RecipeManagement Postman Machine",
"https://oauth.pstmn.io");
recipeManagementPostmanMachineClient.ExtendDefaultScopes(recipemanagementScope.Name);
}
}
public static class ClientExtensions
{
public static void ExtendDefaultScopes(this Client client, params Output<string>[] scopeNames)
{
var defaultScopeName = $"default-scopes-for-{client.Name.Apply(x => x)}";
var defaultScopes = new ClientDefaultScopes(defaultScopeName, new ClientDefaultScopesArgs()
{
RealmId = client.RealmId,
ClientId = client.Id,
DefaultScopes =
{
"openid",
"profile",
"email",
"roles",
"web-origins",
scopeNames,
},
});
}
}
public class ClientFactory
{
public static Client CreateClientCredentialsFlowClient(Output<string> realmId,
string clientId,
string clientSecret,
string clientName,
string baseUrl)
{
return new Client($"{clientName.ToLower()}-client", new ClientArgs()
{
RealmId = realmId,
ClientId = clientId,
Name = clientName,
StandardFlowEnabled = false,
Enabled = true,
ServiceAccountsEnabled = true,
AccessType = "CONFIDENTIAL",
BaseUrl = baseUrl,
AdminUrl = baseUrl,
ClientSecret = clientSecret,
BackchannelLogoutSessionRequired = true,
BackchannelLogoutUrl = baseUrl
});
}
}
The problem is, I am getting this error around my scopes:
Diagnostics:
keycloak:openid:ClientDefaultScopes (default-scopes-for-Calling [ToString] on an [Output<T>] is not supported.
To get the value of an Output<T> as an Output<string> consider:
1. o.Apply(v => $"prefix{v}suffix")
2. Output.Format($"prefix{hostname}suffix");
See https://pulumi.io/help/outputs for more details.
This function may throw in a future version of Pulumi.):
error: Duplicate resource URN 'urn:pulumi:dev::KeycloakPulumiStack::keycloak:openid/clientDefaultScopes:ClientDefaultScopes::default-scopes-for-Calling [ToString] on an [Output<T>] is not supported.
To get the value of an Output<T> as an Output<string> consider:
1. o.Apply(v => $"prefix{v}suffix")
2. Output.Format($"prefix{hostname}suffix");
See https://pulumi.io/help/outputs for more details.
This function may throw in a future version of Pulumi.'; try giving it a unique name
I tried something like this as well var defaultScopeName = Output.Format($"default-scopes-for-{client.Name}");
, but I can't pass that into the name for ClientDefaultScopes
I did look at the docs to see if anything stuck out as an issue, but I'm clearly missing something.
CodePudding user response:
Rule number 1 with Pulumi outputs: Anything you return from an apply()
will still be an Output, even if it looks like it should be a string.
In other words, on this line of code:
var defaultScopeName = $"default-scopes-for-{client.Name.Apply(x => x)}";
defaultScopeName
is Output<string>
.
However, the x
variable in the lambda is in fact a string rather than an output.
The other item to note is that the name of a resource (so the first argument) cannot be an Output. So in your code:
var defaultScopeName = $"default-scopes-for-{client.Name.Apply(x => x)}";
var defaultScopes = new ClientDefaultScopes(defaultScopeName, new ClientDefaultScopesArgs()
{
RealmId = client.RealmId,
ClientId = client.Id,
DefaultScopes =
{
"openid",
"profile",
"email",
"roles",
"web-origins",
scopeNames,
},
});
because defaultScopeName
is an Output, this won't work.
You could create the resource inside of the apply()
:
var defaultScopea = $"default-scopes-for-{client.Name.Apply(x =>
return new ClientDefaultScopes(x, new ClientDefaultScopesArgs()
{
RealmId = client.RealmId,
ClientId = client.Id,
DefaultScopes =
{
"openid",
"profile",
"email",
"roles",
"web-origins",
scopeNames,
},
});
)}";
however, this may mean that the resource won't appear in any previews (see the note in the Apply section of the Inputs and Outputs page in the Pulumi docs).
So what's the answer here? it looks like you're setting the ClientName
to be a string value earlier in the code, so I'd use the same variable that you're setting there.
CodePudding user response:
You can't mix and match string
and Output<string>
values. Instead, you need to transform any output and append your static list to the list of resolved values:
var defaultScopeName = Output.Format($"default-scopes-for-{client.Name}");
var defaultScopes = new ClientDefaultScopes("some-scope-name", new ClientDefaultScopesArgs()
{
RealmId = client.RealmId,
ClientId = client.Id,
DefaultScopes = Output.All(scopeNames).Apply(names =>
new[] { "openid", "profile", "email", "roles", "web-origins", }
.Concat(names)),
});
Note that Output.Format
is used for string formatting, Output.All
is used to convert to Output<string[]>
and .Apply
is used to transform the array. You can learn more in Inputs and Outputs.
CodePudding user response:
Currently, Pulumi only supports string
types for the name of a resource.
Since
var defaultScopeName = $"default-scopes-for-{client.Name.Apply(x => x)}";
is using an output of a resource, defaultScopeName
is type Output<string>
and can't be used for the resource name in the line,
var defaultScopes = new ClientDefaultScopes(defaultScopeName, new ClientDefaultScopesArgs()
If I'm reading the code correctly, you specify clientName
and use it to set client.Name
. So, I would just pass in clientName
and use that instead of client.Name
. And, that should work since it's a basic type all the way through.