@ -41,142 +41,144 @@ namespace Microsoft.Tye
foreach ( var binding in bindings . Bindings )
{
if ( binding is SecretInputBinding secretInputBinding )
if ( ! ( binding is SecretInputBinding secretInputBinding ) )
{
if ( ! Secrets . Add ( secretInputBinding . Name ) )
{
output . WriteDebugLine ( $"Already validated secret '{secretInputBinding.Name}'." ) ;
continue ;
}
continue ;
}
output . WriteDebugLine ( $"Validating secret '{secretInputBinding.Name}'." ) ;
if ( ! Secrets . Add ( secretInputBinding . Name ) )
{
output . WriteDebugLine ( $"Already validated secret '{secretInputBinding.Name}'." ) ;
continue ;
}
var config = KubernetesClientConfiguration . BuildDefaultConfig ( ) ;
output . WriteDebugLine ( $"Validating secret '{secretInputBinding.Name}'." ) ;
// If namespace is null, set it to default
config . Namespace ? ? = "default" ;
var config = KubernetesClientConfiguration . BuildDefaultConfig ( ) ;
var kubernetes = new Kubernetes ( config ) ;
// If namespace is null, set it to default
config . Namespace ? ? = "default" ;
try
{
var result = await kubernetes . ReadNamespacedSecretWithHttpMessagesAsync ( secretInputBinding . Name , config . Namespace ) ;
output . WriteInfoLine ( $"Found existing secret '{secretInputBinding.Name}'." ) ;
continue ;
}
catch ( HttpOperationException ex ) when ( ex . Response . StatusCode = = HttpStatusCode . NotFound )
{
// The kubernetes client uses exceptions for 404s.
}
catch ( Exception ex )
{
output . WriteDebugLine ( "Failed to query secret." ) ;
output . WriteDebugLine ( ex . ToString ( ) ) ;
throw new CommandException ( "Unable connect to kubernetes." , ex ) ;
}
var kubernetes = new Kubernetes ( config ) ;
if ( Force )
{
output . WriteDebugLine ( "Skipping because force was specified." ) ;
continue ;
}
try
{
var result = await kubernetes . ReadNamespacedSecretWithHttpMessagesAsync ( secretInputBinding . Name , config . Namespace ) ;
output . WriteInfoLine ( $"Found existing secret '{secretInputBinding.Name}'." ) ;
continue ;
}
catch ( HttpOperationException ex ) when ( ex . Response . StatusCode = = HttpStatusCode . NotFound )
{
// The kubernetes client uses exceptions for 404s.
}
catch ( Exception ex )
{
output . WriteDebugLine ( "Failed to query secret." ) ;
output . WriteDebugLine ( ex . ToString ( ) ) ;
throw new CommandException ( "Unable connect to kubernetes." , ex ) ;
}
if ( ! Interactive & & secretInputBinding is SecretConnectionStringInputBinding )
{
throw new CommandException (
$"The secret '{secretInputBinding.Name}' used for service '{secretInputBinding.Service.Name}' is missing from the deployment environment. " +
$"Rerun the command with --interactive to specify the value interactively, or with --force to skip validation. Alternatively " +
$"use the following command to manually create the secret." + System . Environment . NewLine +
$"kubectl create secret generic {secretInputBinding.Name} --namespace {config.Namespace} --from-literal=connectionstring=<value>" ) ;
}
if ( Force )
{
output . WriteDebugLine ( "Skipping because force was specified." ) ;
continue ;
}
if ( ! Interactive & & secretInputBinding is SecretConnectionStringInputBinding )
{
throw new CommandException (
$"The secret '{secretInputBinding.Name}' used for service '{secretInputBinding.Service.Name}' is missing from the deployment environment. " +
$"Rerun the command with --interactive to specify the value interactively, or with --force to skip validation. Alternatively " +
$"use the following command to manually create the secret." + System . Environment . NewLine +
$"kubectl create secret generic {secretInputBinding.Name} --namespace {config.Namespace} --from-literal=connectionstring=<value>" ) ;
}
if ( ! Interactive & & secretInputBinding is SecretUrlInputBinding )
if ( ! Interactive & & secretInputBinding is SecretUrlInputBinding )
{
throw new CommandException (
$"The secret '{secretInputBinding.Name}' used for service '{secretInputBinding.Service.Name}' is missing from the deployment environment. " +
$"Rerun the command with --interactive to specify the value interactively, or with --force to skip validation. Alternatively " +
$"use the following command to manually create the secret." + System . Environment . NewLine +
$"kubectl create secret generic {secretInputBinding.Name} --namespace {config.Namespace} --from-literal=protocol=<value> --from-literal=host=<value> --from-literal=port=<value>" ) ;
}
V1Secret secret ;
if ( secretInputBinding is SecretConnectionStringInputBinding )
{
// If we get here then we should create the secret.
var text = output . Prompt ( $"Enter the connection string to use for service '{secretInputBinding.Service.Name}'" , allowEmpty : true ) ;
if ( string . IsNullOrWhiteSpace ( text ) )
{
throw new CommandException (
$"The secret '{secretInputBinding.Name}' used for service '{secretInputBinding.Service.Name}' is missing from the deployment environment. " +
$"Rerun the command with --interactive to specify the value interactively, or with --force to skip validation. Alternatively " +
$"use the following command to manually create the secret." + System . Environment . NewLine +
$"kubectl create secret generic {secretInputBinding.Name} --namespace {config.Namespace} --from-literal=protocol=<value> --from-literal=host=<value> --from-literal=port=<value>" ) ;
output . WriteAlwaysLine ( $"Skipping creation of secret for '{secretInputBinding.Service.Name}'. This may prevent creation of pods until secrets are created." ) ;
output . WriteAlwaysLine ( $"Manually create a secret with:" ) ;
output . WriteAlwaysLine ( $"kubectl create secret generic {secretInputBinding.Name} --namespace {config.Namespace} --from-literal=connectionstring=<value>" ) ;
continue ;
}
V1Secret secret ;
if ( secretInputBinding is SecretConnectionStringInputBinding )
secret = new V1Secret ( type : "Opaque" , stringData : new Dictionary < string , string > ( )
{
// If we get here then we should create the secret.
var text = output . Prompt ( $"Enter the connection string to use for service '{secretInputBinding.Service.Name}'" , allowEmpty : true ) ;
if ( string . IsNullOrWhiteSpace ( text ) )
{
output . WriteAlwaysLine ( $"Skipping creation of secret for '{secretInputBinding.Service.Name}'. This may prevent creation of pods until secrets are created." ) ;
output . WriteAlwaysLine ( $"Manually create a secret with:" ) ;
output . WriteAlwaysLine ( $"kubectl create secret generic {secretInputBinding.Name} --namespace {config.Namespace} --from-literal=connectionstring=<value>" ) ;
continue ;
}
secret = new V1Secret ( type : "Opaque" , stringData : new Dictionary < string , string > ( )
{
{ "connectionstring" , text } ,
} ) ;
}
else if ( secretInputBinding is SecretUrlInputBinding )
{ "connectionstring" , text } ,
} ) ;
}
else if ( secretInputBinding is SecretUrlInputBinding )
{
// If we get here then we should create the secret.
string text ;
Uri ? uri = null ;
while ( true )
{
// If we get here then we should create the secret.
string text ;
Uri ? uri = null ;
while ( true )
text = output . Prompt ( $"Enter the URI to use for service '{secretInputBinding.Service.Name}'" , allowEmpty : true ) ;
if ( string . IsNullOrEmpty ( text ) )
{
text = output . Prompt ( $"Enter the URI to use for service '{secretInputBinding.Service.Name}'" , allowEmpty : true ) ;
if ( string . IsNullOrEmpty ( text ) )
{
break ; // skip
}
else if ( Uri . TryCreate ( text , UriKind . Absolute , out uri ) )
{
break ; // success
}
output . WriteAlwaysLine ( $"Invalid URI: '{text}'" ) ;
break ; // skip
}
if ( string . IsNullOrWhiteSpace ( text ) )
else if ( Uri . TryCreate ( text , UriKind . Absolute , out uri ) )
{
output . WriteAlwaysLine ( $"Skipping creation of secret for '{secretInputBinding.Service.Name}'. This may prevent creation of pods until secrets are created." ) ;
output . WriteAlwaysLine ( $"Manually create a secret with:" ) ;
output . WriteAlwaysLine ( $"kubectl create secret generic {secretInputBinding.Name} --namespace {config.Namespace} --from-literal=protocol=<value> --from-literal=host=<value> --from-literal=port=<value>" ) ;
continue ;
break ; // success
}
secret = new V1Secret ( type : "Opaque" , stringData : new Dictionary < string , string > ( )
{
{ "protocol" , uri ! . Scheme } ,
{ "host" , uri ! . Host } ,
{ "port" , uri ! . Port . ToString ( CultureInfo . InvariantCulture ) } ,
} ) ;
output . WriteAlwaysLine ( $"Invalid URI: '{text}'" ) ;
}
else
if ( string . IsNullOrWhiteSpace ( text ) )
{
throw new InvalidOperationException ( "Unknown Secret type: " + secretInputBinding ) ;
output . WriteAlwaysLine ( $"Skipping creation of secret for '{secretInputBinding.Service.Name}'. This may prevent creation of pods until secrets are created." ) ;
output . WriteAlwaysLine ( $"Manually create a secret with:" ) ;
output . WriteAlwaysLine ( $"kubectl create secret generic {secretInputBinding.Name} --namespace {config.Namespace} --from-literal=protocol=<value> --from-literal=host=<value> --from-literal=port=<value>" ) ;
continue ;
}
secret . Metadata = new V1ObjectMeta ( ) ;
secret . Metadata . Name = secretInputBinding . Name ;
secret . Metadata . Labels = new Dictionary < string , string > ( )
secret = new V1Secret ( type : "Opaque" , stringData : new Dictionary < string , string > ( )
{
["app.kubernetes.io/part-of"] = application . Name ,
} ;
{ "protocol" , uri ! . Scheme } ,
{ "host" , uri ! . Host } ,
{ "port" , uri ! . Port . ToString ( CultureInfo . InvariantCulture ) } ,
} ) ;
}
else
{
throw new InvalidOperationException ( "Unknown Secret type: " + secretInputBinding ) ;
}
output . WriteDebugLine ( $"Creating secret '{secret.Metadata.Name}'." ) ;
secret . Metadata = new V1ObjectMeta ( ) ;
secret . Metadata . Name = secretInputBinding . Name ;
secret . Metadata . Labels = new Dictionary < string , string > ( )
{
["app.kubernetes.io/part-of"] = application . Name ,
} ;
try
{
await kubernetes . CreateNamespacedSecretWithHttpMessagesAsync ( secret , config . Namespace ) ;
output . WriteInfoLine ( $"Created secret '{secret.Metadata.Name}'." ) ;
}
catch ( Exception ex )
{
output . WriteDebugLine ( "Failed to create secret." ) ;
output . WriteDebugLine ( ex . ToString ( ) ) ;
throw new CommandException ( "Failed to create secret." , ex ) ;
}
output . WriteDebugLine ( $"Creating secret '{secret.Metadata.Name}'." ) ;
try
{
await kubernetes . CreateNamespacedSecretWithHttpMessagesAsync ( secret , config . Namespace ) ;
output . WriteInfoLine ( $"Created secret '{secret.Metadata.Name}'." ) ;
}
catch ( Exception ex )
{
output . WriteDebugLine ( "Failed to create secret." ) ;
output . WriteDebugLine ( ex . ToString ( ) ) ;
throw new CommandException ( "Failed to create secret." , ex ) ;
}
}
}