@@ -484,14 +484,20 @@ function isOptionalIntGt0(x?: number): boolean {
484
484
return x === undefined || ( Number . isSafeInteger ( x ) && x > 0 ) ;
485
485
}
486
486
487
+ // Unknown values are encoded as a distinguished string value and passed to the Dynamic Providers `check` method.
488
+ type UnknownValue = "04da6b54-80e4-46f7-96ec-b56ff0331ba9" ;
489
+ const UNKNOWN : UnknownValue = pulumi . runtime . unknownValue ;
490
+ type UnknownInputs < T > = T | Record < keyof T , UnknownValue > ;
491
+
487
492
const defangServiceProvider : pulumi . dynamic . ResourceProvider <
488
493
DefangServiceInputs ,
489
494
DefangServiceOutputs
490
495
> = {
491
496
async check (
492
497
olds : DefangServiceInputs ,
493
- news : DefangServiceInputs
498
+ inputs : DefangServiceInputs
494
499
) : Promise < pulumi . dynamic . CheckResult < DefangServiceInputs > > {
500
+ const news = inputs as UnknownInputs < DefangServiceInputs > ;
495
501
const failures : pulumi . dynamic . CheckFailure [ ] = [ ] ;
496
502
497
503
if ( ! news . fabricDNS ) {
@@ -501,7 +507,7 @@ const defangServiceProvider: pulumi.dynamic.ResourceProvider<
501
507
if ( ! news . name ) {
502
508
failures . push ( { property : "name" , reason : "name is required" } ) ;
503
509
}
504
- if ( news . deploy ) {
510
+ if ( news . deploy && news . deploy !== UNKNOWN ) {
505
511
if ( ! isValidUint ( news . deploy . replicas ?? 0 ) ) {
506
512
failures . push ( {
507
513
property : "deploy" ,
@@ -521,54 +527,59 @@ const defangServiceProvider: pulumi.dynamic.ResourceProvider<
521
527
} ) ;
522
528
}
523
529
}
524
- if ( ! news . deploy ?. resources ?. reservations ?. memory ) {
530
+ if (
531
+ news . deploy !== UNKNOWN &&
532
+ ! news . deploy ?. resources ?. reservations ?. memory
533
+ ) {
525
534
pulumi . log . warn (
526
535
"missing memory reservation; specify deploy.resources.reservations.memory to avoid out-of-memory errors"
527
536
) ;
528
537
}
529
- for ( const port of news . ports || [ ] ) {
530
- // port.protocol = port.protocol || "tcp"; TODO: should we set defaults here?
531
- if (
532
- port . target < 1 ||
533
- port . target > 32767 ||
534
- ! Number . isInteger ( port . target )
535
- ) {
536
- failures . push ( {
537
- property : "ports" ,
538
- reason : "target port must be an integer between 1 and 32767" ,
539
- } ) ;
540
- }
541
- if ( port . mode === "ingress" ) {
542
- if ( [ "udp" , "tcp" ] . includes ( port . protocol ! ) ) {
538
+ if ( news . ports !== UNKNOWN ) {
539
+ for ( const port of news . ports ?? [ ] ) {
540
+ // port.protocol = port.protocol || "tcp"; TODO: should we set defaults here?
541
+ if (
542
+ port . target < 1 ||
543
+ port . target > 32767 ||
544
+ ! Number . isInteger ( port . target )
545
+ ) {
543
546
failures . push ( {
544
547
property : "ports" ,
545
- reason : "ingress is not support by protocol " + port . protocol ,
548
+ reason : "target port must be an integer between 1 and 32767" ,
546
549
} ) ;
547
550
}
548
- if ( ! news . healthcheck ?. test ) {
549
- pulumi . log . warn (
550
- "ingress port without healthcheck defaults to GET / HTTP/1.1"
551
- ) ;
552
- }
553
- }
554
- if ( news . healthcheck ) {
555
- if ( ! isOptionalIntGt0 ( news . healthcheck . interval ) ) {
556
- failures . push ( {
557
- property : "healthcheck.interval" ,
558
- reason : "interval must be an integer > 0" ,
559
- } ) ;
560
- }
561
- if ( ! isOptionalIntGt0 ( news . healthcheck . timeout ) ) {
562
- failures . push ( {
563
- property : "healthcheck.timeout" ,
564
- reason : "timeout must be an integer > 0" ,
565
- } ) ;
551
+ if ( port . mode === "ingress" ) {
552
+ if ( [ "udp" , "tcp" ] . includes ( port . protocol ! ) ) {
553
+ failures . push ( {
554
+ property : "ports" ,
555
+ reason : "ingress is not support by protocol " + port . protocol ,
556
+ } ) ;
557
+ }
558
+ if ( ! news . healthcheck ?. test ) {
559
+ pulumi . log . warn (
560
+ "ingress port without healthcheck defaults to GET / HTTP/1.1"
561
+ ) ;
562
+ }
566
563
}
567
- if ( ! isOptionalIntGt0 ( news . healthcheck . retries ) ) {
568
- failures . push ( {
569
- property : "healthcheck.retries" ,
570
- reason : "retries must be an integer > 0" ,
571
- } ) ;
564
+ if ( news . healthcheck ) {
565
+ if ( ! isOptionalIntGt0 ( news . healthcheck . interval ) ) {
566
+ failures . push ( {
567
+ property : "healthcheck.interval" ,
568
+ reason : "interval must be an integer > 0" ,
569
+ } ) ;
570
+ }
571
+ if ( ! isOptionalIntGt0 ( news . healthcheck . timeout ) ) {
572
+ failures . push ( {
573
+ property : "healthcheck.timeout" ,
574
+ reason : "timeout must be an integer > 0" ,
575
+ } ) ;
576
+ }
577
+ if ( ! isOptionalIntGt0 ( news . healthcheck . retries ) ) {
578
+ failures . push ( {
579
+ property : "healthcheck.retries" ,
580
+ reason : "retries must be an integer > 0" ,
581
+ } ) ;
582
+ }
572
583
}
573
584
}
574
585
}
@@ -578,13 +589,15 @@ const defangServiceProvider: pulumi.dynamic.ResourceProvider<
578
589
reason : "only one network can be specified" ,
579
590
} ) ;
580
591
}
581
- for ( const secret of news . secrets || [ ] ) {
582
- // TODO: validate source name
583
- if ( ! secret . source ) {
584
- failures . push ( {
585
- property : "secrets" ,
586
- reason : "secret source is required" ,
587
- } ) ;
592
+ if ( news . secrets !== UNKNOWN ) {
593
+ for ( const secret of news . secrets || [ ] ) {
594
+ // TODO: validate source name
595
+ if ( ! secret . source ) {
596
+ failures . push ( {
597
+ property : "secrets" ,
598
+ reason : "secret source is required" ,
599
+ } ) ;
600
+ }
588
601
}
589
602
}
590
603
if ( news . build ) {
@@ -594,34 +607,36 @@ const defangServiceProvider: pulumi.dynamic.ResourceProvider<
594
607
reason : "cannot specify both build and image" ,
595
608
} ) ;
596
609
}
597
- if ( ! news . build . context ) {
598
- failures . push ( {
599
- property : "build.context" ,
600
- reason : "build context is required" ,
601
- } ) ;
602
- }
603
- if ( news . build . dockerfile === "" ) {
604
- failures . push ( {
605
- property : "build.dockerfile" ,
606
- reason : "dockerfile cannot be empty string" ,
607
- } ) ;
608
- }
609
- if ( ! isOptionalFloatGt0 ( news . build . shmSize ) ) {
610
- failures . push ( {
611
- property : "build.shmSize" ,
612
- reason : "shmSize must be an integer > 0" ,
613
- } ) ;
614
- }
615
- if ( news . build . target === "" ) {
616
- failures . push ( {
617
- property : "build.target" ,
618
- reason : "target cannot be empty string" ,
619
- } ) ;
610
+ if ( news . build !== UNKNOWN ) {
611
+ if ( ! news . build . context ) {
612
+ failures . push ( {
613
+ property : "build.context" ,
614
+ reason : "build context is required" ,
615
+ } ) ;
616
+ }
617
+ if ( news . build . dockerfile === "" ) {
618
+ failures . push ( {
619
+ property : "build.dockerfile" ,
620
+ reason : "dockerfile cannot be empty string" ,
621
+ } ) ;
622
+ }
623
+ if ( ! isOptionalFloatGt0 ( news . build . shmSize ) ) {
624
+ failures . push ( {
625
+ property : "build.shmSize" ,
626
+ reason : "shmSize must be an integer > 0" ,
627
+ } ) ;
628
+ }
629
+ if ( news . build . target === "" ) {
630
+ failures . push ( {
631
+ property : "build.target" ,
632
+ reason : "target cannot be empty string" ,
633
+ } ) ;
634
+ }
620
635
}
621
636
} else if ( ! news . image ) {
622
637
failures . push ( { property : "image" , reason : "image is required" } ) ;
623
638
}
624
- return { inputs : news , failures } ;
639
+ return { inputs, failures } ;
625
640
} ,
626
641
async create (
627
642
inputs : DefangServiceInputs
0 commit comments