@@ -14,6 +14,7 @@ import * as logs from '../../aws-logs';
14
14
import * as route53 from '../../aws-route53' ;
15
15
import * as secretsmanager from '../../aws-secretsmanager' ;
16
16
import * as cdk from '../../core' ;
17
+ import { ValidationError } from '../../core' ;
17
18
import { addConstructMetadata , MethodMetadata } from '../../core/lib/metadata-resource' ;
18
19
19
20
/**
@@ -1487,7 +1488,7 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable {
1487
1488
props . zoneAwareness ?. availabilityZoneCount ?? 2 ;
1488
1489
1489
1490
if ( ! [ 2 , 3 ] . includes ( availabilityZoneCount ) ) {
1490
- throw new Error ( 'Invalid zone awareness configuration; availabilityZoneCount must be 2 or 3' ) ;
1491
+ throw new ValidationError ( 'Invalid zone awareness configuration; availabilityZoneCount must be 2 or 3' , this ) ;
1491
1492
}
1492
1493
1493
1494
const zoneAwarenessEnabled =
@@ -1508,19 +1509,19 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable {
1508
1509
1509
1510
// If VPC options are supplied ensure that the number of subnets matches the number AZ
1510
1511
if ( subnets && zoneAwarenessEnabled && new Set ( subnets . map ( ( subnet ) => subnet . availabilityZone ) ) . size < availabilityZoneCount ) {
1511
- throw new Error ( 'When providing vpc options you need to provide a subnet for each AZ you are using' ) ;
1512
+ throw new ValidationError ( 'When providing vpc options you need to provide a subnet for each AZ you are using' , this ) ;
1512
1513
}
1513
1514
1514
1515
if ( [ dedicatedMasterType , instanceType , warmType ] . some ( t => ( ! cdk . Token . isUnresolved ( t ) && ! t . endsWith ( '.elasticsearch' ) ) ) ) {
1515
- throw new Error ( 'Master, data and UltraWarm node instance types must end with ".elasticsearch".' ) ;
1516
+ throw new ValidationError ( 'Master, data and UltraWarm node instance types must end with ".elasticsearch".' , this ) ;
1516
1517
}
1517
1518
1518
1519
if ( ! cdk . Token . isUnresolved ( warmType ) && ! warmType . startsWith ( 'ultrawarm' ) ) {
1519
- throw new Error ( 'UltraWarm node instance type must start with "ultrawarm".' ) ;
1520
+ throw new ValidationError ( 'UltraWarm node instance type must start with "ultrawarm".' , this ) ;
1520
1521
}
1521
1522
1522
1523
const elasticsearchVersion = props . version . version ;
1523
- const elasticsearchVersionNum = parseVersion ( props . version ) ;
1524
+ const elasticsearchVersionNum = parseVersion ( this , props . version ) ;
1524
1525
1525
1526
if (
1526
1527
elasticsearchVersionNum <= 7.7 &&
@@ -1530,20 +1531,20 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable {
1530
1531
7.7 ,
1531
1532
] . includes ( elasticsearchVersionNum )
1532
1533
) {
1533
- throw new Error ( `Unknown Elasticsearch version: ${ elasticsearchVersion } ` ) ;
1534
+ throw new ValidationError ( `Unknown Elasticsearch version: ${ elasticsearchVersion } ` , this ) ;
1534
1535
}
1535
1536
1536
1537
const unsignedBasicAuthEnabled = props . useUnsignedBasicAuth ?? false ;
1537
1538
1538
1539
if ( unsignedBasicAuthEnabled ) {
1539
1540
if ( props . enforceHttps == false ) {
1540
- throw new Error ( 'You cannot disable HTTPS and use unsigned basic auth' ) ;
1541
+ throw new ValidationError ( 'You cannot disable HTTPS and use unsigned basic auth' , this ) ;
1541
1542
}
1542
1543
if ( props . nodeToNodeEncryption == false ) {
1543
- throw new Error ( 'You cannot disable node to node encryption and use unsigned basic auth' ) ;
1544
+ throw new ValidationError ( 'You cannot disable node to node encryption and use unsigned basic auth' , this ) ;
1544
1545
}
1545
1546
if ( props . encryptionAtRest ?. enabled == false ) {
1546
- throw new Error ( 'You cannot disable encryption at rest and use unsigned basic auth' ) ;
1547
+ throw new ValidationError ( 'You cannot disable encryption at rest and use unsigned basic auth' , this ) ;
1547
1548
}
1548
1549
}
1549
1550
@@ -1562,7 +1563,7 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable {
1562
1563
: masterUserNameProps ;
1563
1564
1564
1565
if ( masterUserArn != null && masterUserName != null ) {
1565
- throw new Error ( 'Invalid fine grained access control settings. Only provide one of master user ARN or master user name. Not both.' ) ;
1566
+ throw new ValidationError ( 'Invalid fine grained access control settings. Only provide one of master user ARN or master user name. Not both.' , this ) ;
1566
1567
}
1567
1568
1568
1569
const advancedSecurityEnabled = ( masterUserArn ?? masterUserName ) != null ;
@@ -1608,86 +1609,86 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable {
1608
1609
// https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/aes-features-by-version.html
1609
1610
if ( elasticsearchVersionNum < 5.1 ) {
1610
1611
if ( props . logging ?. appLogEnabled ) {
1611
- throw new Error ( 'Error logs publishing requires Elasticsearch version 5.1 or later.' ) ;
1612
+ throw new ValidationError ( 'Error logs publishing requires Elasticsearch version 5.1 or later.' , this ) ;
1612
1613
}
1613
1614
if ( props . encryptionAtRest ?. enabled ) {
1614
- throw new Error ( 'Encryption of data at rest requires Elasticsearch version 5.1 or later.' ) ;
1615
+ throw new ValidationError ( 'Encryption of data at rest requires Elasticsearch version 5.1 or later.' , this ) ;
1615
1616
}
1616
1617
if ( props . cognitoKibanaAuth != null ) {
1617
- throw new Error ( 'Cognito authentication for Kibana requires Elasticsearch version 5.1 or later.' ) ;
1618
+ throw new ValidationError ( 'Cognito authentication for Kibana requires Elasticsearch version 5.1 or later.' , this ) ;
1618
1619
}
1619
1620
if ( isSomeInstanceType ( 'c5' , 'i3' , 'm5' , 'r5' ) ) {
1620
- throw new Error ( 'C5, I3, M5, and R5 instance types require Elasticsearch version 5.1 or later.' ) ;
1621
+ throw new ValidationError ( 'C5, I3, M5, and R5 instance types require Elasticsearch version 5.1 or later.' , this ) ;
1621
1622
}
1622
1623
}
1623
1624
1624
1625
if ( elasticsearchVersionNum < 6.0 ) {
1625
1626
if ( props . nodeToNodeEncryption ) {
1626
- throw new Error ( 'Node-to-node encryption requires Elasticsearch version 6.0 or later.' ) ;
1627
+ throw new ValidationError ( 'Node-to-node encryption requires Elasticsearch version 6.0 or later.' , this ) ;
1627
1628
}
1628
1629
}
1629
1630
1630
1631
if ( elasticsearchVersionNum < 6.7 ) {
1631
1632
if ( unsignedBasicAuthEnabled ) {
1632
- throw new Error ( 'Using unsigned basic auth requires Elasticsearch version 6.7 or later.' ) ;
1633
+ throw new ValidationError ( 'Using unsigned basic auth requires Elasticsearch version 6.7 or later.' , this ) ;
1633
1634
}
1634
1635
if ( advancedSecurityEnabled ) {
1635
- throw new Error ( 'Fine-grained access control requires Elasticsearch version 6.7 or later.' ) ;
1636
+ throw new ValidationError ( 'Fine-grained access control requires Elasticsearch version 6.7 or later.' , this ) ;
1636
1637
}
1637
1638
}
1638
1639
1639
1640
if ( elasticsearchVersionNum < 6.8 && warmEnabled ) {
1640
- throw new Error ( 'UltraWarm requires Elasticsearch 6.8 or later.' ) ;
1641
+ throw new ValidationError ( 'UltraWarm requires Elasticsearch 6.8 or later.' , this ) ;
1641
1642
}
1642
1643
1643
1644
// Validate against instance type restrictions, per
1644
1645
// https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/aes-supported-instance-types.html
1645
1646
if ( isSomeInstanceType ( 'i3' , 'r6gd' ) && ebsEnabled ) {
1646
- throw new Error ( 'I3 and R6GD instance types do not support EBS storage volumes.' ) ;
1647
+ throw new ValidationError ( 'I3 and R6GD instance types do not support EBS storage volumes.' , this ) ;
1647
1648
}
1648
1649
1649
1650
if ( isSomeInstanceType ( 'm3' , 'r3' , 't2' ) && encryptionAtRestEnabled ) {
1650
- throw new Error ( 'M3, R3, and T2 instance types do not support encryption of data at rest.' ) ;
1651
+ throw new ValidationError ( 'M3, R3, and T2 instance types do not support encryption of data at rest.' , this ) ;
1651
1652
}
1652
1653
1653
1654
if ( isInstanceType ( 't2.micro' ) && elasticsearchVersionNum > 2.3 ) {
1654
- throw new Error ( 'The t2.micro.elasticsearch instance type supports only Elasticsearch 1.5 and 2.3.' ) ;
1655
+ throw new ValidationError ( 'The t2.micro.elasticsearch instance type supports only Elasticsearch 1.5 and 2.3.' , this ) ;
1655
1656
}
1656
1657
1657
1658
if ( isSomeInstanceType ( 't2' , 't3' ) && warmEnabled ) {
1658
- throw new Error ( 'T2 and T3 instance types do not support UltraWarm storage.' ) ;
1659
+ throw new ValidationError ( 'T2 and T3 instance types do not support UltraWarm storage.' , this ) ;
1659
1660
}
1660
1661
1661
1662
// Only R3, I3 and r6gd support instance storage, per
1662
1663
// https://aws.amazon.com/elasticsearch-service/pricing/
1663
1664
if ( ! ebsEnabled && ! isEveryDatanodeInstanceType ( 'r3' , 'i3' , 'r6gd' ) ) {
1664
- throw new Error ( 'EBS volumes are required when using instance types other than r3, i3 or r6gd.' ) ;
1665
+ throw new ValidationError ( 'EBS volumes are required when using instance types other than r3, i3 or r6gd.' , this ) ;
1665
1666
}
1666
1667
1667
1668
// Fine-grained access control requires node-to-node encryption, encryption at rest,
1668
1669
// and enforced HTTPS.
1669
1670
if ( advancedSecurityEnabled ) {
1670
1671
if ( ! nodeToNodeEncryptionEnabled ) {
1671
- throw new Error ( 'Node-to-node encryption is required when fine-grained access control is enabled.' ) ;
1672
+ throw new ValidationError ( 'Node-to-node encryption is required when fine-grained access control is enabled.' , this ) ;
1672
1673
}
1673
1674
if ( ! encryptionAtRestEnabled ) {
1674
- throw new Error ( 'Encryption-at-rest is required when fine-grained access control is enabled.' ) ;
1675
+ throw new ValidationError ( 'Encryption-at-rest is required when fine-grained access control is enabled.' , this ) ;
1675
1676
}
1676
1677
if ( ! enforceHttps ) {
1677
- throw new Error ( 'Enforce HTTPS is required when fine-grained access control is enabled.' ) ;
1678
+ throw new ValidationError ( 'Enforce HTTPS is required when fine-grained access control is enabled.' , this ) ;
1678
1679
}
1679
1680
}
1680
1681
1681
1682
// Validate fine grained access control enabled for audit logs, per
1682
1683
// https://aws.amazon.com/about-aws/whats-new/2020/09/elasticsearch-audit-logs-now-available-on-amazon-elasticsearch-service/
1683
1684
if ( props . logging ?. auditLogEnabled && ! advancedSecurityEnabled ) {
1684
- throw new Error ( 'Fine-grained access control is required when audit logs publishing is enabled.' ) ;
1685
+ throw new ValidationError ( 'Fine-grained access control is required when audit logs publishing is enabled.' , this ) ;
1685
1686
}
1686
1687
1687
1688
// Validate UltraWarm requirement for dedicated master nodes, per
1688
1689
// https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/ultrawarm.html
1689
1690
if ( warmEnabled && ! dedicatedMasterEnabled ) {
1690
- throw new Error ( 'Dedicated master node is required when UltraWarm storage is enabled.' ) ;
1691
+ throw new ValidationError ( 'Dedicated master node is required when UltraWarm storage is enabled.' , this ) ;
1691
1692
}
1692
1693
1693
1694
let cfnVpcOptions : CfnDomain . VPCOptionsProperty | undefined ;
@@ -1887,13 +1888,13 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable {
1887
1888
if ( ! cdk . Token . isUnresolved ( props . domainName ) ) {
1888
1889
// https://docs.aws.amazon.com/opensearch-service/latest/developerguide/configuration-api.html#configuration-api-datatypes-domainname
1889
1890
if ( ! props . domainName . match ( / ^ [ a - z 0 - 9 \- ] + $ / ) ) {
1890
- throw new Error ( `Invalid domainName '${ props . domainName } '. Valid characters are a-z (lowercase only), 0-9, and – (hyphen).` ) ;
1891
+ throw new ValidationError ( `Invalid domainName '${ props . domainName } '. Valid characters are a-z (lowercase only), 0-9, and – (hyphen).` , this ) ;
1891
1892
}
1892
1893
if ( props . domainName . length < 3 || props . domainName . length > 28 ) {
1893
- throw new Error ( `Invalid domainName '${ props . domainName } '. It must be between 3 and 28 characters` ) ;
1894
+ throw new ValidationError ( `Invalid domainName '${ props . domainName } '. It must be between 3 and 28 characters` , this ) ;
1894
1895
}
1895
1896
if ( props . domainName [ 0 ] < 'a' || props . domainName [ 0 ] > 'z' ) {
1896
- throw new Error ( `Invalid domainName '${ props . domainName } '. It must start with a lowercase letter` ) ;
1897
+ throw new ValidationError ( `Invalid domainName '${ props . domainName } '. It must start with a lowercase letter` , this ) ;
1897
1898
}
1898
1899
}
1899
1900
this . node . addMetadata ( 'aws:cdk:hasPhysicalName' , props . domainName ) ;
@@ -1934,7 +1935,7 @@ export class Domain extends DomainBase implements IDomain, ec2.IConnectable {
1934
1935
*/
1935
1936
public get connections ( ) : ec2 . Connections {
1936
1937
if ( ! this . _connections ) {
1937
- throw new Error ( "Connections are only available on VPC enabled domains. Use the 'vpc' property to place a domain inside a VPC" ) ;
1938
+ throw new ValidationError ( "Connections are only available on VPC enabled domains. Use the 'vpc' property to place a domain inside a VPC" , this ) ;
1938
1939
}
1939
1940
return this . _connections ;
1940
1941
}
@@ -2001,12 +2002,12 @@ function extractNameFromEndpoint(domainEndpoint: string) {
2001
2002
*
2002
2003
* @param version The Elasticsearch version object
2003
2004
*/
2004
- function parseVersion ( version : ElasticsearchVersion ) : number {
2005
+ function parseVersion ( scope : Construct , version : ElasticsearchVersion ) : number {
2005
2006
const versionStr = version . version ;
2006
2007
const firstDot = versionStr . indexOf ( '.' ) ;
2007
2008
2008
2009
if ( firstDot < 1 ) {
2009
- throw new Error ( `Invalid Elasticsearch version: ${ versionStr } . Version string needs to start with major and minor version (x.y).` ) ;
2010
+ throw new ValidationError ( `Invalid Elasticsearch version: ${ versionStr } . Version string needs to start with major and minor version (x.y).` , scope ) ;
2010
2011
}
2011
2012
2012
2013
const secondDot = versionStr . indexOf ( '.' , firstDot + 1 ) ;
@@ -2018,7 +2019,7 @@ function parseVersion(version: ElasticsearchVersion): number {
2018
2019
return parseFloat ( versionStr . substring ( 0 , secondDot ) ) ;
2019
2020
}
2020
2021
} catch {
2021
- throw new Error ( `Invalid Elasticsearch version: ${ versionStr } . Version string needs to start with major and minor version (x.y).` ) ;
2022
+ throw new ValidationError ( `Invalid Elasticsearch version: ${ versionStr } . Version string needs to start with major and minor version (x.y).` , scope ) ;
2022
2023
}
2023
2024
}
2024
2025
0 commit comments