diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md index b110aef2..adfd0a91 100644 --- a/ATTRIBUTION.md +++ b/ATTRIBUTION.md @@ -20,6 +20,7 @@ include an indication of the Open Source License under which that package is distributed. For any package *NOT* distributed under the terms of the Apache License version 2.0, we include the full text of the package's License below. +* `github.com/aws-controllers-k8s/iam-controller` * `github.com/aws-controllers-k8s/runtime` * `github.com/aws/aws-sdk-go` * `github.com/aws/aws-sdk-go-v2` @@ -34,34 +35,26 @@ License version 2.0, we include the full text of the package's License below. * `k8s.io/client-go` * `sigs.k8s.io/controller-runtime` -### github.com/aws-controllers-k8s/runtime +### github.com/aws-controllers-k8s/iam-controller License Identifier: Apache-2.0 Subdependencies: +* `github.com/aws-controllers-k8s/runtime` +* `github.com/aws/aws-sdk-go` * `github.com/aws/aws-sdk-go-v2` -* `github.com/aws/aws-sdk-go-v2/config` -* `github.com/aws/aws-sdk-go-v2/credentials` -* `github.com/aws/aws-sdk-go-v2/service/sts` +* `github.com/aws/aws-sdk-go-v2/service/iam` * `github.com/aws/smithy-go` -* `github.com/cenkalti/backoff/v4` * `github.com/go-logr/logr` -* `github.com/go-logr/zapr` -* `github.com/google/go-cmp` -* `github.com/itchyny/gojq` -* `github.com/jaypipes/envutil` * `github.com/micahhausler/aws-iam-policy` -* `github.com/pkg/errors` -* `github.com/prometheus/client_golang` +* `github.com/samber/lo` * `github.com/spf13/pflag` -* `github.com/stretchr/testify` -* `go.uber.org/zap` * `k8s.io/api` * `k8s.io/apimachinery` * `k8s.io/client-go` -* `k8s.io/klog/v2` -* `k8s.io/utils` * `sigs.k8s.io/controller-runtime` +* `github.com/aws/aws-sdk-go-v2/config` +* `github.com/aws/aws-sdk-go-v2/credentials` * `github.com/aws/aws-sdk-go-v2/feature/ec2/imds` * `github.com/aws/aws-sdk-go-v2/internal/configsources` * `github.com/aws/aws-sdk-go-v2/internal/endpoints/v2` @@ -70,36 +63,45 @@ Subdependencies: * `github.com/aws/aws-sdk-go-v2/service/internal/presigned-url` * `github.com/aws/aws-sdk-go-v2/service/sso` * `github.com/aws/aws-sdk-go-v2/service/ssooidc` +* `github.com/aws/aws-sdk-go-v2/service/sts` * `github.com/beorn7/perks` +* `github.com/cenkalti/backoff/v4` * `github.com/cespare/xxhash/v2` * `github.com/davecgh/go-spew` * `github.com/emicklei/go-restful/v3` -* `github.com/evanphx/json-patch` * `github.com/evanphx/json-patch/v5` * `github.com/fsnotify/fsnotify` * `github.com/fxamacker/cbor/v2` +* `github.com/go-logr/zapr` * `github.com/go-openapi/jsonpointer` * `github.com/go-openapi/jsonreference` * `github.com/go-openapi/swag` * `github.com/google/btree` * `github.com/google/gnostic-models` +* `github.com/google/go-cmp` * `github.com/google/uuid` +* `github.com/itchyny/gojq` * `github.com/itchyny/timefmt-go` +* `github.com/jaypipes/envutil` +* `github.com/jmespath/go-jmespath` * `github.com/josharian/intern` * `github.com/json-iterator/go` * `github.com/mailru/easyjson` * `github.com/modern-go/concurrent` * `github.com/modern-go/reflect2` * `github.com/munnerz/goautoneg` +* `github.com/pkg/errors` * `github.com/pmezard/go-difflib` +* `github.com/prometheus/client_golang` * `github.com/prometheus/client_model` * `github.com/prometheus/common` * `github.com/prometheus/procfs` -* `github.com/stretchr/objx` * `github.com/x448/float16` * `go.uber.org/multierr` +* `go.uber.org/zap` * `go.yaml.in/yaml/v2` * `go.yaml.in/yaml/v3` +* `golang.org/x/exp` * `golang.org/x/net` * `golang.org/x/oauth2` * `golang.org/x/sync` @@ -113,25 +115,27 @@ Subdependencies: * `gopkg.in/inf.v0` * `gopkg.in/yaml.v3` * `k8s.io/apiextensions-apiserver` +* `k8s.io/klog/v2` * `k8s.io/kube-openapi` +* `k8s.io/utils` * `sigs.k8s.io/json` * `sigs.k8s.io/randfill` * `sigs.k8s.io/structured-merge-diff/v6` * `sigs.k8s.io/yaml` -#### github.com/aws/aws-sdk-go-v2 +#### github.com/aws-controllers-k8s/runtime License Identifier: Apache-2.0 -#### github.com/aws/aws-sdk-go-v2/config +#### github.com/aws/aws-sdk-go License Identifier: Apache-2.0 -#### github.com/aws/aws-sdk-go-v2/credentials +#### github.com/aws/aws-sdk-go-v2 License Identifier: Apache-2.0 -#### github.com/aws/aws-sdk-go-v2/service/sts +#### github.com/aws/aws-sdk-go-v2/service/iam License Identifier: Apache-2.0 @@ -139,78 +143,31 @@ License Identifier: Apache-2.0 License Identifier: Apache-2.0 -#### github.com/cenkalti/backoff/v4 - -License Identifier: MIT - -The MIT License (MIT) - -Copyright (c) 2014 Cenk Altı - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - #### github.com/go-logr/logr License Identifier: Apache-2.0 -#### github.com/go-logr/zapr - -License Identifier: Apache-2.0 +#### github.com/micahhausler/aws-iam-policy -#### github.com/google/go-cmp +License Identifier: MIT -License Identifier: BSD-3-Clause +The MIT License (MIT) -Copyright (c) 2017 The Go Authors. All rights reserved. +Copyright (c) 2023, Micah Hausler -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -#### github.com/itchyny/gojq +#### github.com/samber/lo License Identifier: MIT -The MIT License (MIT) +MIT License -Copyright (c) 2019-2021 itchyny +Copyright (c) 2022 Samuel Berthe Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -230,56 +187,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -#### github.com/jaypipes/envutil - -License Identifier: Apache-2.0 - -#### github.com/micahhausler/aws-iam-policy - -License Identifier: MIT - -The MIT License (MIT) - -Copyright (c) 2023, Micah Hausler - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#### github.com/pkg/errors - -License Identifier: BSD-2-Clause - -Copyright (c) 2015, Dave Cheney -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#### github.com/prometheus/client_golang - -License Identifier: Apache-2.0 - #### github.com/spf13/pflag License Identifier: BSD-3-Clause @@ -313,54 +220,6 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#### github.com/stretchr/testify - -License Identifier: MIT - -MIT License - -Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -#### go.uber.org/zap - -Copyright (c) 2016-2017 Uber Technologies, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - #### k8s.io/api License Identifier: Apache-2.0 @@ -373,15 +232,15 @@ License Identifier: Apache-2.0 License Identifier: Apache-2.0 -#### k8s.io/klog/v2 +#### sigs.k8s.io/controller-runtime License Identifier: Apache-2.0 -#### k8s.io/utils +#### github.com/aws/aws-sdk-go-v2/config License Identifier: Apache-2.0 -#### sigs.k8s.io/controller-runtime +#### github.com/aws/aws-sdk-go-v2/credentials License Identifier: Apache-2.0 @@ -417,6 +276,10 @@ License Identifier: Apache-2.0 License Identifier: Apache-2.0 +#### github.com/aws/aws-sdk-go-v2/service/sts + +License Identifier: Apache-2.0 + #### github.com/beorn7/perks Copyright (C) 2013 Blake Mizerany @@ -440,6 +303,31 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +#### github.com/cenkalti/backoff/v4 + +License Identifier: MIT + +The MIT License (MIT) + +Copyright (c) 2014 Cenk Altı + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + #### github.com/cespare/xxhash/v2 License Identifier: MIT @@ -514,36 +402,6 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -#### github.com/evanphx/json-patch - -License Identifier: BSD-3-Clause - -Copyright (c) 2014, Evan Phoenix -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. -* Neither the name of the Evan Phoenix nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - #### github.com/evanphx/json-patch/v5 License Identifier: BSD-3-Clause @@ -630,6 +488,10 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +#### github.com/go-logr/zapr + +License Identifier: Apache-2.0 + #### github.com/go-openapi/jsonpointer License Identifier: Apache-2.0 @@ -650,6 +512,38 @@ License Identifier: Apache-2.0 License Identifier: Apache-2.0 +#### github.com/google/go-cmp + +License Identifier: BSD-3-Clause + +Copyright (c) 2017 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + #### github.com/google/uuid License Identifier: BSD-3-Clause @@ -682,6 +576,32 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#### github.com/itchyny/gojq + +License Identifier: MIT + +The MIT License (MIT) + +Copyright (c) 2019-2021 itchyny + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + #### github.com/itchyny/timefmt-go License Identifier: MIT @@ -708,6 +628,14 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +#### github.com/jaypipes/envutil + +License Identifier: Apache-2.0 + +#### github.com/jmespath/go-jmespath + +License Identifier: Apache-2.0 + #### github.com/josharian/intern License Identifier: MIT @@ -814,6 +742,34 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#### github.com/pkg/errors + +License Identifier: BSD-2-Clause + +Copyright (c) 2015, Dave Cheney +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + #### github.com/pmezard/go-difflib License Identifier: BSD-3-Clause @@ -846,6 +802,10 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#### github.com/prometheus/client_golang + +License Identifier: Apache-2.0 + #### github.com/prometheus/client_model License Identifier: Apache-2.0 @@ -858,14 +818,13 @@ License Identifier: Apache-2.0 License Identifier: Apache-2.0 -#### github.com/stretchr/objx +#### github.com/x448/float16 License Identifier: MIT -The MIT License +MIT License -Copyright (c) 2014 Stretchr, Inc. -Copyright (c) 2017-2018 objx contributors +Copyright (c) 2019 Montgomery Edwards⁴⁴⁸ and Faye Amacker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -885,13 +844,9 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -#### github.com/x448/float16 - -License Identifier: MIT - -MIT License +#### go.uber.org/multierr -Copyright (c) 2019 Montgomery Edwards⁴⁴⁸ and Faye Amacker +Copyright (c) 2017-2021 Uber Technologies, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -900,20 +855,20 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. -#### go.uber.org/multierr +#### go.uber.org/zap -Copyright (c) 2017-2021 Uber Technologies, Inc. +Copyright (c) 2016-2017 Uber Technologies, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -941,6 +896,38 @@ License Identifier: Apache-2.0 License Identifier: Apache-2.0 +#### golang.org/x/exp + +License Identifier: BSD-3-Clause + +Copyright 2009 The Go Authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google LLC nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + #### golang.org/x/net License Identifier: BSD-3-Clause @@ -1272,10 +1259,18 @@ License Identifier: Apache-2.0 License Identifier: Apache-2.0 +#### k8s.io/klog/v2 + +License Identifier: Apache-2.0 + #### k8s.io/kube-openapi License Identifier: Apache-2.0 +#### k8s.io/utils + +License Identifier: Apache-2.0 + #### sigs.k8s.io/json License Identifier: BSD-3-Clause @@ -1531,18 +1526,9 @@ License Identifier: Apache-2.0 License Identifier: Apache-2.0 -### github.com/aws/aws-sdk-go -License Identifier: Apache-2.0 -Subdependencies: -* `github.com/jmespath/go-jmespath` -* `golang.org/x/net` -* `golang.org/x/text` - -#### github.com/jmespath/go-jmespath -License Identifier: Apache-2.0 ### github.com/aws/aws-sdk-go-v2 @@ -1571,13 +1557,17 @@ Subdependencies: -### github.com/samber/lo + + + + +### github.com/stretchr/testify License Identifier: MIT MIT License -Copyright (c) 2022 Samuel Berthe +Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -1599,43 +1589,41 @@ SOFTWARE. Subdependencies: -* `golang.org/x/exp` +* `github.com/davecgh/go-spew` +* `github.com/pmezard/go-difflib` +* `github.com/stretchr/objx` +* `gopkg.in/yaml.v3` -#### golang.org/x/exp -License Identifier: BSD-3-Clause -Copyright 2009 The Go Authors. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google LLC nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. +#### github.com/stretchr/objx -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +License Identifier: MIT +The MIT License +Copyright (c) 2014 Stretchr, Inc. +Copyright (c) 2017-2018 objx contributors +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/apis/v1alpha1/ack-generate-metadata.yaml b/apis/v1alpha1/ack-generate-metadata.yaml index 2ae1d5ab..a0f8eee4 100755 --- a/apis/v1alpha1/ack-generate-metadata.yaml +++ b/apis/v1alpha1/ack-generate-metadata.yaml @@ -1,13 +1,13 @@ ack_generate_info: - build_date: "2026-03-31T20:49:31Z" + build_date: "2026-04-02T11:13:56Z" build_hash: a9e2ceaadfc00a742e2ea2b6d6c68348f03e52a5 go_version: go1.26.1 version: v0.58.0-3-ga9e2cea -api_directory_checksum: 3dca3992dafa3c55cf11ec49bf1b3084c01ae8d6 +api_directory_checksum: 823aebd7d4f0327f14769caf14f00f5378f743a8 api_version: v1alpha1 aws_sdk_go_version: v1.41.1 generator_config_info: - file_checksum: 7d17e806218e4f31db5006de1aa270afb85e867e + file_checksum: 4a0d22e950c89e235e2e34dc86cd1babcb562466 original_file_name: generator.yaml last_modification: reason: API generation diff --git a/apis/v1alpha1/fleet.go b/apis/v1alpha1/fleet.go new file mode 100644 index 00000000..cfc19f0f --- /dev/null +++ b/apis/v1alpha1/fleet.go @@ -0,0 +1,153 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package v1alpha1 + +import ( + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// FleetSpec defines the desired state of Fleet. +type FleetSpec struct { + + // Reserved. + Context *string `json:"context,omitempty"` + // Indicates whether running instances should be terminated if the total target + // capacity of the EC2 Fleet is decreased below the current size of the EC2 + // Fleet. + // + // Supported only for fleets of type maintain. + ExcessCapacityTerminationPolicy *string `json:"excessCapacityTerminationPolicy,omitempty"` + // The configuration for the EC2 Fleet. + // +kubebuilder:validation:Required + LaunchTemplateConfigs []*FleetLaunchTemplateConfigRequest `json:"launchTemplateConfigs"` + // Describes the configuration of On-Demand Instances in an EC2 Fleet. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable once set" + OnDemandOptions *OnDemandOptionsRequest `json:"onDemandOptions,omitempty"` + // Indicates whether EC2 Fleet should replace unhealthy Spot Instances. Supported + // only for fleets of type maintain. For more information, see EC2 Fleet health + // checks (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/manage-ec2-fleet.html#ec2-fleet-health-checks) + // in the Amazon EC2 User Guide. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable once set" + ReplaceUnhealthyInstances *bool `json:"replaceUnhealthyInstances,omitempty"` + // Describes the configuration of Spot Instances in an EC2 Fleet. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable once set" + SpotOptions *SpotOptionsRequest `json:"spotOptions,omitempty"` + // The tags. The value parameter is required, but if you don't want the tag + // to have a value, specify the parameter with no value, and we set the value + // to an empty string. + Tags []*Tag `json:"tags,omitempty"` + // The number of units to request. + // +kubebuilder:validation:Required + TargetCapacitySpecification *TargetCapacitySpecificationRequest `json:"targetCapacitySpecification"` + TerminateInstancesOnDeletion *bool `json:"terminateInstancesOnDeletion,omitempty"` + // Indicates whether running instances should be terminated when the EC2 Fleet + // expires. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable once set" + TerminateInstancesWithExpiration *bool `json:"terminateInstancesWithExpiration,omitempty"` + // The fleet type. The default value is maintain. + // + // - maintain - The EC2 Fleet places an asynchronous request for your desired + // capacity, and continues to maintain your desired Spot capacity by replenishing + // interrupted Spot Instances. + // + // - request - The EC2 Fleet places an asynchronous one-time request for + // your desired capacity, but does submit Spot requests in alternative capacity + // pools if Spot capacity is unavailable, and does not maintain Spot capacity + // if Spot Instances are interrupted. + // + // - instant - The EC2 Fleet places a synchronous one-time request for your + // desired capacity, and returns errors for any instances that could not + // be launched. + // + // For more information, see EC2 Fleet request types (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-request-type.html) + // in the Amazon EC2 User Guide. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable once set" + Type *string `json:"type,omitempty"` + // The start date and time of the request, in UTC format (for example, YYYY-MM-DDTHH:MM:SSZ). + // The default is to start fulfilling the request immediately. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable once set" + ValidFrom *metav1.Time `json:"validFrom,omitempty"` + // The end date and time of the request, in UTC format (for example, YYYY-MM-DDTHH:MM:SSZ). + // At this point, no new EC2 Fleet requests are placed or able to fulfill the + // request. If no value is specified, the request remains until you cancel it. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable once set" + ValidUntil *metav1.Time `json:"validUntil,omitempty"` +} + +// FleetStatus defines the observed state of Fleet +type FleetStatus struct { + // All CRs managed by ACK have a common `Status.ACKResourceMetadata` member + // that is used to contain resource sync state, account ownership, + // constructed ARN for the resource + // +kubebuilder:validation:Optional + ACKResourceMetadata *ackv1alpha1.ResourceMetadata `json:"ackResourceMetadata"` + // All CRs managed by ACK have a common `Status.Conditions` member that + // contains a collection of `ackv1alpha1.Condition` objects that describe + // the various terminal states of the CR and its backend AWS service API + // resource + // +kubebuilder:validation:Optional + Conditions []*ackv1alpha1.Condition `json:"conditions"` + // The progress of the EC2 Fleet. + // + // For fleets of type instant, the status is fulfilled after all requests are + // placed, regardless of whether target capacity is met (this is the only possible + // status for instant fleets). + // + // For fleets of type request or maintain, the status is pending_fulfillment + // after all requests are placed, fulfilled when the fleet size meets or exceeds + // target capacity, pending_termination while instances are terminating when + // fleet size is decreased, and error if there's an error. + // +kubebuilder:validation:Optional + ActivityStatus *string `json:"activityStatus,omitempty"` + // Information about the instances that could not be launched by the fleet. + // Supported only for fleets of type instant. + // +kubebuilder:validation:Optional + Errors []*CreateFleetError `json:"errors,omitempty"` + // The ID of the EC2 Fleet. + // +kubebuilder:validation:Optional + FleetID *string `json:"fleetID,omitempty"` + // The state of the EC2 Fleet. + // +kubebuilder:validation:Optional + FleetState *string `json:"fleetState,omitempty"` + // The number of units fulfilled by this request compared to the set target + // capacity. + // +kubebuilder:validation:Optional + FulfilledCapacity *float64 `json:"fulfilledCapacity,omitempty"` +} + +// Fleet is the Schema for the Fleets API +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="ID",type=string,priority=0,JSONPath=`.status.fleetID` +type Fleet struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec FleetSpec `json:"spec,omitempty"` + Status FleetStatus `json:"status,omitempty"` +} + +// FleetList contains a list of Fleet +// +kubebuilder:object:root=true +type FleetList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Fleet `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Fleet{}, &FleetList{}) +} diff --git a/apis/v1alpha1/generator.yaml b/apis/v1alpha1/generator.yaml index f2c76e1c..ad83102d 100644 --- a/apis/v1alpha1/generator.yaml +++ b/apis/v1alpha1/generator.yaml @@ -155,6 +155,12 @@ ignore: - ManagedPrefixList.IpamPrefixListResolverSyncEnabled - ManagedPrefixList.IpamPrefixListResolverTargetId - CreateLaunchTemplateVersionOutput.LaunchTemplateVersion.DefaultVersion + - CreateFleetInput.ClientToken + - CreateFleetInput.TagSpecifications + - CreateFleetInput.DryRun + - CreateFleetOutput.Instances + - FleetLaunchTemplateOverrides.AvailabilityZoneId + - FleetLaunchTemplateOverridesRequest.AvailabilityZoneId resource_names: - CapacityReservationBySplitting - IpamExternalResourceVerificationToken @@ -174,7 +180,7 @@ ignore: - DelegateMacVolumeOwnershipTask #- DhcpOptions - EgressOnlyInternetGateway - - Fleet + # - Fleet - FpgaImage - Image - ImageUsageReport @@ -320,6 +326,10 @@ operations: operation_type: - Delete resource_name: FlowLog + DeleteFleets: + operation_type: + - Delete + resource_name: Fleet RunInstances: #ouput shape: Reservation output_wrapper_field_path: Instances @@ -1264,3 +1274,99 @@ resources: template_path: hooks/vpc_peering_connection/sdk_read_many_post_set_output.go.tpl sdk_file_end: template_path: hooks/vpc_peering_connection/sdk_file_end.go.tpl + Fleet: + fields: + FleetID: + is_primary_key: true + is_read_only: true + print: + name: ID + Tags: + from: + operation: CreateTags + path: Tags + FleetState: + is_read_only: true + from: + operation: DescribeFleets + path: Fleets.FleetState + ActivityStatus: + is_read_only: true + from: + operation: DescribeFleets + path: Fleets.ActivityStatus + FulfilledCapacity: + is_read_only: true + from: + operation: DescribeFleets + path: Fleets.FulfilledCapacity + Type: + late_initialize: + skip_incomplete_check: {} + is_immutable: true + go_tag: json:"type,omitempty" + TerminateInstancesOnDeletion: + type: bool + ReplaceUnhealthyInstances: + late_initialize: + skip_incomplete_check: {} + is_immutable: true + TerminateInstancesWithExpiration: + late_initialize: + skip_incomplete_check: {} + is_immutable: true + ExcessCapacityTerminationPolicy: + late_initialize: + skip_incomplete_check: {} + SpotOptions: + late_initialize: + skip_incomplete_check: {} + is_immutable: true + OnDemandOptions: + late_initialize: + skip_incomplete_check: {} + is_immutable: true + ValidFrom: + late_initialize: + skip_incomplete_check: {} + is_immutable: true + ValidUntil: + late_initialize: + skip_incomplete_check: {} + is_immutable: true + TargetCapacitySpecification.OnDemandTargetCapacity: + late_initialize: + skip_incomplete_check: {} + TargetCapacitySpecification.SpotTargetCapacity: + late_initialize: + skip_incomplete_check: {} + TargetCapacitySpecification.DefaultTargetCapacityType: + is_immutable: true + synced: + when: + - path: Status.ActivityStatus + in: + - fulfilled + - path: Status.FleetState + in: + - active + exceptions: + terminal_codes: + - InvalidParameterValue + hooks: + delta_pre_compare: + code: customPreCompare(delta, a, b) + sdk_create_post_build_request: + template_path: hooks/fleet/sdk_create_post_build_request.go.tpl + sdk_read_many_post_set_output: + template_path: hooks/fleet/sdk_read_many_post_set_output.go.tpl + sdk_delete_pre_build_request: + template_path: hooks/fleet/sdk_delete_pre_build_request.go.tpl + sdk_delete_post_build_request: + template_path: hooks/fleet/sdk_delete_post_build_request.go.tpl + sdk_update_pre_build_request: + template_path: hooks/fleet/sdk_update_pre_build_request.go.tpl + sdk_update_pre_set_output: + template_path: hooks/fleet/sdk_update_pre_set_output.go.tpl + sdk_file_end: + template_path: hooks/fleet/sdk_file_end.go.tpl diff --git a/apis/v1alpha1/types.go b/apis/v1alpha1/types.go index 5e5a7d96..afaaea97 100644 --- a/apis/v1alpha1/types.go +++ b/apis/v1alpha1/types.go @@ -445,9 +445,11 @@ type BlockDeviceMapping struct { // Describes a block device mapping, which defines the EBS volumes and instance // store volumes to attach to an instance at launch. type BlockDeviceMappingResponse struct { - DeviceName *string `json:"deviceName,omitempty"` - NoDevice *string `json:"noDevice,omitempty"` - VirtualName *string `json:"virtualName,omitempty"` + DeviceName *string `json:"deviceName,omitempty"` + // Describes a block device for an EBS volume. + EBS *EBSBlockDeviceResponse `json:"ebs,omitempty"` + NoDevice *string `json:"noDevice,omitempty"` + VirtualName *string `json:"virtualName,omitempty"` } // Describes a bundle task. @@ -693,6 +695,34 @@ type CapacityReservationInfo struct { Tenancy *string `json:"tenancy,omitempty"` } +// Describes the strategy for using unused Capacity Reservations for fulfilling +// On-Demand capacity. +// +// This strategy can only be used if the EC2 Fleet is of type instant. +// +// For more information about Capacity Reservations, see On-Demand Capacity +// Reservations (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-capacity-reservations.html) +// in the Amazon EC2 User Guide. For examples of using Capacity Reservations +// in an EC2 Fleet, see EC2 Fleet example configurations (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-examples.html) +// in the Amazon EC2 User Guide. +type CapacityReservationOptions struct { + UsageStrategy *string `json:"usageStrategy,omitempty"` +} + +// Describes the strategy for using unused Capacity Reservations for fulfilling +// On-Demand capacity. +// +// This strategy can only be used if the EC2 Fleet is of type instant. +// +// For more information about Capacity Reservations, see On-Demand Capacity +// Reservations (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-capacity-reservations.html) +// in the Amazon EC2 User Guide. For examples of using Capacity Reservations +// in an EC2 Fleet, see EC2 Fleet example configurations (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-examples.html) +// in the Amazon EC2 User Guide. +type CapacityReservationOptionsRequest struct { + UsageStrategy *string `json:"usageStrategy,omitempty"` +} + // Describes an instance's Capacity Reservation targeting option. // // Use the CapacityReservationPreference parameter to configure the instance @@ -1062,12 +1092,19 @@ type ConversionTask struct { type CreateFleetError struct { ErrorCode *string `json:"errorCode,omitempty"` ErrorMessage *string `json:"errorMessage,omitempty"` + // Describes a launch template and overrides. + LaunchTemplateAndOverrides *LaunchTemplateAndOverridesResponse `json:"launchTemplateAndOverrides,omitempty"` + Lifecycle *string `json:"lifecycle,omitempty"` } // Describes the instances that were launched by the fleet. type CreateFleetInstance struct { - InstanceType *string `json:"instanceType,omitempty"` - Platform *string `json:"platform,omitempty"` + InstanceIDs []*string `json:"instanceIDs,omitempty"` + InstanceType *string `json:"instanceType,omitempty"` + // Describes a launch template and overrides. + LaunchTemplateAndOverrides *LaunchTemplateAndOverridesResponse `json:"launchTemplateAndOverrides,omitempty"` + Lifecycle *string `json:"lifecycle,omitempty"` + Platform *string `json:"platform,omitempty"` } type CreateRouteInput struct { @@ -1245,9 +1282,24 @@ type DeclarativePoliciesReport struct { // Describes an EC2 Fleet error. type DeleteFleetError struct { + Code *string `json:"code,omitempty"` Message *string `json:"message,omitempty"` } +// Describes an EC2 Fleet that was not successfully deleted. +type DeleteFleetErrorItem struct { + // Describes an EC2 Fleet error. + Error *DeleteFleetError `json:"error,omitempty"` + FleetID *string `json:"fleetID,omitempty"` +} + +// Describes an EC2 Fleet that was successfully deleted. +type DeleteFleetSuccessItem struct { + CurrentFleetState *string `json:"currentFleetState,omitempty"` + FleetID *string `json:"fleetID,omitempty"` + PreviousFleetState *string `json:"previousFleetState,omitempty"` +} + // Describes a launch template version that could not be deleted. type DeleteLaunchTemplateVersionsResponseErrorItem struct { LaunchTemplateID *string `json:"launchTemplateID,omitempty"` @@ -1311,12 +1363,19 @@ type DescribeFastSnapshotRestoreSuccessItem struct { type DescribeFleetError struct { ErrorCode *string `json:"errorCode,omitempty"` ErrorMessage *string `json:"errorMessage,omitempty"` + // Describes a launch template and overrides. + LaunchTemplateAndOverrides *LaunchTemplateAndOverridesResponse `json:"launchTemplateAndOverrides,omitempty"` + Lifecycle *string `json:"lifecycle,omitempty"` } // Describes the instances that were launched by the fleet. type DescribeFleetsInstances struct { - InstanceType *string `json:"instanceType,omitempty"` - Platform *string `json:"platform,omitempty"` + InstanceIDs []*string `json:"instanceIDs,omitempty"` + InstanceType *string `json:"instanceType,omitempty"` + // Describes a launch template and overrides. + LaunchTemplateAndOverrides *LaunchTemplateAndOverridesResponse `json:"launchTemplateAndOverrides,omitempty"` + Lifecycle *string `json:"lifecycle,omitempty"` + Platform *string `json:"platform,omitempty"` } // Describes the destination options for a flow log. @@ -1818,9 +1877,11 @@ type FirewallStatelessRule struct { // // - Specify all desired parameters here. type FleetBlockDeviceMappingRequest struct { - DeviceName *string `json:"deviceName,omitempty"` - NoDevice *string `json:"noDevice,omitempty"` - VirtualName *string `json:"virtualName,omitempty"` + DeviceName *string `json:"deviceName,omitempty"` + // Describes a block device for an EBS volume. + EBS *FleetEBSBlockDeviceRequest `json:"ebs,omitempty"` + NoDevice *string `json:"noDevice,omitempty"` + VirtualName *string `json:"virtualName,omitempty"` } // Information about a Capacity Reservation in a Capacity Reservation Fleet. @@ -1838,16 +1899,44 @@ type FleetCapacityReservation struct { // Describes an EC2 Fleet. type FleetData struct { - ClientToken *string `json:"clientToken,omitempty"` - Context *string `json:"context,omitempty"` - CreateTime *metav1.Time `json:"createTime,omitempty"` - FulfilledCapacity *float64 `json:"fulfilledCapacity,omitempty"` - FulfilledOnDemandCapacity *float64 `json:"fulfilledOnDemandCapacity,omitempty"` - ReplaceUnhealthyInstances *bool `json:"replaceUnhealthyInstances,omitempty"` - Tags []*Tag `json:"tags,omitempty"` - TerminateInstancesWithExpiration *bool `json:"terminateInstancesWithExpiration,omitempty"` - ValidFrom *metav1.Time `json:"validFrom,omitempty"` - ValidUntil *metav1.Time `json:"validUntil,omitempty"` + ActivityStatus *string `json:"activityStatus,omitempty"` + ClientToken *string `json:"clientToken,omitempty"` + Context *string `json:"context,omitempty"` + CreateTime *metav1.Time `json:"createTime,omitempty"` + Errors []*DescribeFleetError `json:"errors,omitempty"` + ExcessCapacityTerminationPolicy *string `json:"excessCapacityTerminationPolicy,omitempty"` + FleetID *string `json:"fleetID,omitempty"` + FleetState *string `json:"fleetState,omitempty"` + FulfilledCapacity *float64 `json:"fulfilledCapacity,omitempty"` + FulfilledOnDemandCapacity *float64 `json:"fulfilledOnDemandCapacity,omitempty"` + Instances []*DescribeFleetsInstances `json:"instances,omitempty"` + LaunchTemplateConfigs []*FleetLaunchTemplateConfig `json:"launchTemplateConfigs,omitempty"` + // Describes the configuration of On-Demand Instances in an EC2 Fleet. + OnDemandOptions *OnDemandOptions `json:"onDemandOptions,omitempty"` + ReplaceUnhealthyInstances *bool `json:"replaceUnhealthyInstances,omitempty"` + // Describes the configuration of Spot Instances in an EC2 Fleet. + SpotOptions *SpotOptions `json:"spotOptions,omitempty"` + Tags []*Tag `json:"tags,omitempty"` + // The number of units to request. You can choose to set the target capacity + // in terms of instances or a performance characteristic that is important to + // your application workload, such as vCPUs, memory, or I/O. If the request + // type is maintain, you can specify a target capacity of 0 and add capacity + // later. + // + // You can use the On-Demand Instance MaxTotalPrice parameter, the Spot Instance + // MaxTotalPrice, or both to ensure that your fleet cost does not exceed your + // budget. If you set a maximum price per hour for the On-Demand Instances and + // Spot Instances in your request, EC2 Fleet will launch instances until it + // reaches the maximum amount that you're willing to pay. When the maximum amount + // you're willing to pay is reached, the fleet stops launching instances even + // if it hasn’t met the target capacity. The MaxTotalPrice parameters are + // located in OnDemandOptions (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_OnDemandOptions.html) + // and SpotOptions (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_SpotOptions). + TargetCapacitySpecification *TargetCapacitySpecification `json:"targetCapacitySpecification,omitempty"` + TerminateInstancesWithExpiration *bool `json:"terminateInstancesWithExpiration,omitempty"` + Type *string `json:"type_,omitempty"` + ValidFrom *metav1.Time `json:"validFrom,omitempty"` + ValidUntil *metav1.Time `json:"validUntil,omitempty"` } // Describes a block device for an EBS volume. @@ -1862,11 +1951,37 @@ type FleetEBSBlockDeviceRequest struct { VolumeType *string `json:"volumeType,omitempty"` } +// Describes a launch template and overrides. +type FleetLaunchTemplateConfig struct { + // The Amazon EC2 launch template that can be used by a Spot Fleet to configure + // Amazon EC2 instances. You must specify either the ID or name of the launch + // template in the request, but not both. + // + // For information about launch templates, see Launch an instance from a launch + // template (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-templates.html) + // in the Amazon EC2 User Guide. + LaunchTemplateSpecification *FleetLaunchTemplateSpecification `json:"launchTemplateSpecification,omitempty"` + Overrides []*FleetLaunchTemplateOverrides `json:"overrides,omitempty"` +} + +// Describes a launch template and overrides. +type FleetLaunchTemplateConfigRequest struct { + // The Amazon EC2 launch template that can be used by an EC2 Fleet to configure + // Amazon EC2 instances. You must specify either the ID or name of the launch + // template in the request, but not both. + // + // For information about launch templates, see Launch an instance from a launch + // template (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-templates.html) + // in the Amazon EC2 User Guide. + LaunchTemplateSpecification *FleetLaunchTemplateSpecificationRequest `json:"launchTemplateSpecification,omitempty"` + Overrides []*FleetLaunchTemplateOverridesRequest `json:"overrides,omitempty"` +} + // Describes overrides for a launch template. type FleetLaunchTemplateOverrides struct { - AvailabilityZone *string `json:"availabilityZone,omitempty"` - AvailabilityZoneID *string `json:"availabilityZoneID,omitempty"` - ImageID *string `json:"imageID,omitempty"` + AvailabilityZone *string `json:"availabilityZone,omitempty"` + BlockDeviceMappings []*BlockDeviceMappingResponse `json:"blockDeviceMappings,omitempty"` + ImageID *string `json:"imageID,omitempty"` // The attributes for the instance types. When you specify instance attributes, // Amazon EC2 will identify instance types with these attributes. // @@ -1904,16 +2019,18 @@ type FleetLaunchTemplateOverrides struct { InstanceRequirements *InstanceRequirements `json:"instanceRequirements,omitempty"` InstanceType *string `json:"instanceType,omitempty"` MaxPrice *string `json:"maxPrice,omitempty"` - Priority *float64 `json:"priority,omitempty"` - SubnetID *string `json:"subnetID,omitempty"` - WeightedCapacity *float64 `json:"weightedCapacity,omitempty"` + // Describes the placement of an instance. + Placement *PlacementResponse `json:"placement,omitempty"` + Priority *float64 `json:"priority,omitempty"` + SubnetID *string `json:"subnetID,omitempty"` + WeightedCapacity *float64 `json:"weightedCapacity,omitempty"` } // Describes overrides for a launch template. type FleetLaunchTemplateOverridesRequest struct { - AvailabilityZone *string `json:"availabilityZone,omitempty"` - AvailabilityZoneID *string `json:"availabilityZoneID,omitempty"` - ImageID *string `json:"imageID,omitempty"` + AvailabilityZone *string `json:"availabilityZone,omitempty"` + BlockDeviceMappings []*FleetBlockDeviceMappingRequest `json:"blockDeviceMappings,omitempty"` + ImageID *string `json:"imageID,omitempty"` // The attributes for the instance types. When you specify instance attributes, // Amazon EC2 will identify instance types with these attributes. // @@ -1986,7 +2103,8 @@ type FleetLaunchTemplateSpecificationRequest struct { // The strategy to use when Amazon EC2 emits a signal that your Spot Instance // is at an elevated risk of being interrupted. type FleetSpotCapacityRebalance struct { - TerminationDelay *int64 `json:"terminationDelay,omitempty"` + ReplacementStrategy *string `json:"replacementStrategy,omitempty"` + TerminationDelay *int64 `json:"terminationDelay,omitempty"` } // The Spot Instance replacement strategy to use when Amazon EC2 emits a rebalance @@ -1994,7 +2112,26 @@ type FleetSpotCapacityRebalance struct { // interrupted. For more information, see Capacity rebalancing (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-capacity-rebalance.html) // in the Amazon EC2 User Guide. type FleetSpotCapacityRebalanceRequest struct { - TerminationDelay *int64 `json:"terminationDelay,omitempty"` + ReplacementStrategy *string `json:"replacementStrategy,omitempty"` + TerminationDelay *int64 `json:"terminationDelay,omitempty"` +} + +// The strategies for managing your Spot Instances that are at an elevated risk +// of being interrupted. +type FleetSpotMaintenanceStrategies struct { + // The strategy to use when Amazon EC2 emits a signal that your Spot Instance + // is at an elevated risk of being interrupted. + CapacityRebalance *FleetSpotCapacityRebalance `json:"capacityRebalance,omitempty"` +} + +// The strategies for managing your Spot Instances that are at an elevated risk +// of being interrupted. +type FleetSpotMaintenanceStrategiesRequest struct { + // The Spot Instance replacement strategy to use when Amazon EC2 emits a rebalance + // notification signal that your Spot Instance is at an elevated risk of being + // interrupted. For more information, see Capacity rebalancing (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-capacity-rebalance.html) + // in the Amazon EC2 User Guide. + CapacityRebalance *FleetSpotCapacityRebalanceRequest `json:"capacityRebalance,omitempty"` } // Describes a flow log. @@ -3669,6 +3806,20 @@ type LaunchSpecification struct { UserData *string `json:"userData,omitempty"` } +// Describes a launch template and overrides. +type LaunchTemplateAndOverridesResponse struct { + // The Amazon EC2 launch template that can be used by a Spot Fleet to configure + // Amazon EC2 instances. You must specify either the ID or name of the launch + // template in the request, but not both. + // + // For information about launch templates, see Launch an instance from a launch + // template (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-templates.html) + // in the Amazon EC2 User Guide. + LaunchTemplateSpecification *FleetLaunchTemplateSpecification `json:"launchTemplateSpecification,omitempty"` + // Describes overrides for a launch template. + Overrides *FleetLaunchTemplateOverrides `json:"overrides,omitempty"` +} + // Describes a block device mapping. type LaunchTemplateBlockDeviceMapping struct { DeviceName *string `json:"deviceName,omitempty"` @@ -3721,6 +3872,18 @@ type LaunchTemplateCapacityReservationSpecificationResponse struct { CapacityReservationTarget *CapacityReservationTargetResponse `json:"capacityReservationTarget,omitempty"` } +// Describes a launch template and overrides. +type LaunchTemplateConfig struct { + // The Amazon EC2 launch template that can be used by a Spot Fleet to configure + // Amazon EC2 instances. You must specify either the ID or name of the launch + // template in the request, but not both. + // + // For information about launch templates, see Launch an instance from a launch + // template (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-templates.html) + // in the Amazon EC2 User Guide. + LaunchTemplateSpecification *FleetLaunchTemplateSpecification `json:"launchTemplateSpecification,omitempty"` +} + // Describes a block device for an EBS volume. type LaunchTemplateEBSBlockDevice struct { DeleteOnTermination *bool `json:"deleteOnTermination,omitempty"` @@ -4660,18 +4823,42 @@ type OIDCOptions struct { // Describes the configuration of On-Demand Instances in an EC2 Fleet. type OnDemandOptions struct { - MaxTotalPrice *string `json:"maxTotalPrice,omitempty"` - MinTargetCapacity *int64 `json:"minTargetCapacity,omitempty"` - SingleAvailabilityZone *bool `json:"singleAvailabilityZone,omitempty"` - SingleInstanceType *bool `json:"singleInstanceType,omitempty"` + AllocationStrategy *string `json:"allocationStrategy,omitempty"` + // Describes the strategy for using unused Capacity Reservations for fulfilling + // On-Demand capacity. + // + // This strategy can only be used if the EC2 Fleet is of type instant. + // + // For more information about Capacity Reservations, see On-Demand Capacity + // Reservations (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-capacity-reservations.html) + // in the Amazon EC2 User Guide. For examples of using Capacity Reservations + // in an EC2 Fleet, see EC2 Fleet example configurations (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-examples.html) + // in the Amazon EC2 User Guide. + CapacityReservationOptions *CapacityReservationOptions `json:"capacityReservationOptions,omitempty"` + MaxTotalPrice *string `json:"maxTotalPrice,omitempty"` + MinTargetCapacity *int64 `json:"minTargetCapacity,omitempty"` + SingleAvailabilityZone *bool `json:"singleAvailabilityZone,omitempty"` + SingleInstanceType *bool `json:"singleInstanceType,omitempty"` } // Describes the configuration of On-Demand Instances in an EC2 Fleet. type OnDemandOptionsRequest struct { - MaxTotalPrice *string `json:"maxTotalPrice,omitempty"` - MinTargetCapacity *int64 `json:"minTargetCapacity,omitempty"` - SingleAvailabilityZone *bool `json:"singleAvailabilityZone,omitempty"` - SingleInstanceType *bool `json:"singleInstanceType,omitempty"` + AllocationStrategy *string `json:"allocationStrategy,omitempty"` + // Describes the strategy for using unused Capacity Reservations for fulfilling + // On-Demand capacity. + // + // This strategy can only be used if the EC2 Fleet is of type instant. + // + // For more information about Capacity Reservations, see On-Demand Capacity + // Reservations (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-capacity-reservations.html) + // in the Amazon EC2 User Guide. For examples of using Capacity Reservations + // in an EC2 Fleet, see EC2 Fleet example configurations (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-examples.html) + // in the Amazon EC2 User Guide. + CapacityReservationOptions *CapacityReservationOptionsRequest `json:"capacityReservationOptions,omitempty"` + MaxTotalPrice *string `json:"maxTotalPrice,omitempty"` + MinTargetCapacity *int64 `json:"minTargetCapacity,omitempty"` + SingleAvailabilityZone *bool `json:"singleAvailabilityZone,omitempty"` + SingleInstanceType *bool `json:"singleInstanceType,omitempty"` } // Describes whether the resource is managed by a service provider and, if so, @@ -6115,7 +6302,9 @@ type SpotFleetRequestConfigData struct { SpotMaxTotalPrice *string `json:"spotMaxTotalPrice,omitempty"` SpotPrice *string `json:"spotPrice,omitempty"` TargetCapacity *int64 `json:"targetCapacity,omitempty"` + TargetCapacityUnitType *string `json:"targetCapacityUnitType,omitempty"` TerminateInstancesWithExpiration *bool `json:"terminateInstancesWithExpiration,omitempty"` + Type *string `json:"type_,omitempty"` ValidFrom *metav1.Time `json:"validFrom,omitempty"` ValidUntil *metav1.Time `json:"validUntil,omitempty"` } @@ -6169,20 +6358,30 @@ type SpotMarketOptions struct { // Describes the configuration of Spot Instances in an EC2 Fleet. type SpotOptions struct { - InstancePoolsToUseCount *int64 `json:"instancePoolsToUseCount,omitempty"` - MaxTotalPrice *string `json:"maxTotalPrice,omitempty"` - MinTargetCapacity *int64 `json:"minTargetCapacity,omitempty"` - SingleAvailabilityZone *bool `json:"singleAvailabilityZone,omitempty"` - SingleInstanceType *bool `json:"singleInstanceType,omitempty"` + AllocationStrategy *string `json:"allocationStrategy,omitempty"` + InstanceInterruptionBehavior *string `json:"instanceInterruptionBehavior,omitempty"` + InstancePoolsToUseCount *int64 `json:"instancePoolsToUseCount,omitempty"` + // The strategies for managing your Spot Instances that are at an elevated risk + // of being interrupted. + MaintenanceStrategies *FleetSpotMaintenanceStrategies `json:"maintenanceStrategies,omitempty"` + MaxTotalPrice *string `json:"maxTotalPrice,omitempty"` + MinTargetCapacity *int64 `json:"minTargetCapacity,omitempty"` + SingleAvailabilityZone *bool `json:"singleAvailabilityZone,omitempty"` + SingleInstanceType *bool `json:"singleInstanceType,omitempty"` } // Describes the configuration of Spot Instances in an EC2 Fleet request. type SpotOptionsRequest struct { - InstancePoolsToUseCount *int64 `json:"instancePoolsToUseCount,omitempty"` - MaxTotalPrice *string `json:"maxTotalPrice,omitempty"` - MinTargetCapacity *int64 `json:"minTargetCapacity,omitempty"` - SingleAvailabilityZone *bool `json:"singleAvailabilityZone,omitempty"` - SingleInstanceType *bool `json:"singleInstanceType,omitempty"` + AllocationStrategy *string `json:"allocationStrategy,omitempty"` + InstanceInterruptionBehavior *string `json:"instanceInterruptionBehavior,omitempty"` + InstancePoolsToUseCount *int64 `json:"instancePoolsToUseCount,omitempty"` + // The strategies for managing your Spot Instances that are at an elevated risk + // of being interrupted. + MaintenanceStrategies *FleetSpotMaintenanceStrategiesRequest `json:"maintenanceStrategies,omitempty"` + MaxTotalPrice *string `json:"maxTotalPrice,omitempty"` + MinTargetCapacity *int64 `json:"minTargetCapacity,omitempty"` + SingleAvailabilityZone *bool `json:"singleAvailabilityZone,omitempty"` + SingleInstanceType *bool `json:"singleInstanceType,omitempty"` } // Describes Spot Instance placement. @@ -6389,9 +6588,11 @@ type TagSpecification struct { // located in OnDemandOptions (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_OnDemandOptions.html) // and SpotOptions (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_SpotOptions). type TargetCapacitySpecification struct { - OnDemandTargetCapacity *int64 `json:"onDemandTargetCapacity,omitempty"` - SpotTargetCapacity *int64 `json:"spotTargetCapacity,omitempty"` - TotalTargetCapacity *int64 `json:"totalTargetCapacity,omitempty"` + DefaultTargetCapacityType *string `json:"defaultTargetCapacityType,omitempty"` + OnDemandTargetCapacity *int64 `json:"onDemandTargetCapacity,omitempty"` + SpotTargetCapacity *int64 `json:"spotTargetCapacity,omitempty"` + TargetCapacityUnitType *string `json:"targetCapacityUnitType,omitempty"` + TotalTargetCapacity *int64 `json:"totalTargetCapacity,omitempty"` } // The number of units to request. You can choose to set the target capacity @@ -6410,9 +6611,12 @@ type TargetCapacitySpecification struct { // parameters are located in OnDemandOptionsRequest (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_OnDemandOptionsRequest) // and SpotOptionsRequest (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_SpotOptionsRequest). type TargetCapacitySpecificationRequest struct { - OnDemandTargetCapacity *int64 `json:"onDemandTargetCapacity,omitempty"` - SpotTargetCapacity *int64 `json:"spotTargetCapacity,omitempty"` - TotalTargetCapacity *int64 `json:"totalTargetCapacity,omitempty"` + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable once set" + DefaultTargetCapacityType *string `json:"defaultTargetCapacityType,omitempty"` + OnDemandTargetCapacity *int64 `json:"onDemandTargetCapacity,omitempty"` + SpotTargetCapacity *int64 `json:"spotTargetCapacity,omitempty"` + TargetCapacityUnitType *string `json:"targetCapacityUnitType,omitempty"` + TotalTargetCapacity *int64 `json:"totalTargetCapacity,omitempty"` } // Information about the Convertible Reserved Instance offering. diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go index bb0d244f..8bb135f5 100644 --- a/apis/v1alpha1/zz_generated.deepcopy.go +++ b/apis/v1alpha1/zz_generated.deepcopy.go @@ -1476,6 +1476,11 @@ func (in *BlockDeviceMappingResponse) DeepCopyInto(out *BlockDeviceMappingRespon *out = new(string) **out = **in } + if in.EBS != nil { + in, out := &in.EBS, &out.EBS + *out = new(EBSBlockDeviceResponse) + (*in).DeepCopyInto(*out) + } if in.NoDevice != nil { in, out := &in.NoDevice, &out.NoDevice *out = new(string) @@ -2546,6 +2551,46 @@ func (in *CapacityReservationList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CapacityReservationOptions) DeepCopyInto(out *CapacityReservationOptions) { + *out = *in + if in.UsageStrategy != nil { + in, out := &in.UsageStrategy, &out.UsageStrategy + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CapacityReservationOptions. +func (in *CapacityReservationOptions) DeepCopy() *CapacityReservationOptions { + if in == nil { + return nil + } + out := new(CapacityReservationOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CapacityReservationOptionsRequest) DeepCopyInto(out *CapacityReservationOptionsRequest) { + *out = *in + if in.UsageStrategy != nil { + in, out := &in.UsageStrategy, &out.UsageStrategy + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CapacityReservationOptionsRequest. +func (in *CapacityReservationOptionsRequest) DeepCopy() *CapacityReservationOptionsRequest { + if in == nil { + return nil + } + out := new(CapacityReservationOptionsRequest) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CapacityReservationSpec) DeepCopyInto(out *CapacityReservationSpec) { *out = *in @@ -4231,6 +4276,16 @@ func (in *CreateFleetError) DeepCopyInto(out *CreateFleetError) { *out = new(string) **out = **in } + if in.LaunchTemplateAndOverrides != nil { + in, out := &in.LaunchTemplateAndOverrides, &out.LaunchTemplateAndOverrides + *out = new(LaunchTemplateAndOverridesResponse) + (*in).DeepCopyInto(*out) + } + if in.Lifecycle != nil { + in, out := &in.Lifecycle, &out.Lifecycle + *out = new(string) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CreateFleetError. @@ -4246,11 +4301,32 @@ func (in *CreateFleetError) DeepCopy() *CreateFleetError { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CreateFleetInstance) DeepCopyInto(out *CreateFleetInstance) { *out = *in + if in.InstanceIDs != nil { + in, out := &in.InstanceIDs, &out.InstanceIDs + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } if in.InstanceType != nil { in, out := &in.InstanceType, &out.InstanceType *out = new(string) **out = **in } + if in.LaunchTemplateAndOverrides != nil { + in, out := &in.LaunchTemplateAndOverrides, &out.LaunchTemplateAndOverrides + *out = new(LaunchTemplateAndOverridesResponse) + (*in).DeepCopyInto(*out) + } + if in.Lifecycle != nil { + in, out := &in.Lifecycle, &out.Lifecycle + *out = new(string) + **out = **in + } if in.Platform != nil { in, out := &in.Platform, &out.Platform *out = new(string) @@ -5190,6 +5266,11 @@ func (in *DeclarativePoliciesReport) DeepCopy() *DeclarativePoliciesReport { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DeleteFleetError) DeepCopyInto(out *DeleteFleetError) { *out = *in + if in.Code != nil { + in, out := &in.Code, &out.Code + *out = new(string) + **out = **in + } if in.Message != nil { in, out := &in.Message, &out.Message *out = new(string) @@ -5207,6 +5288,61 @@ func (in *DeleteFleetError) DeepCopy() *DeleteFleetError { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeleteFleetErrorItem) DeepCopyInto(out *DeleteFleetErrorItem) { + *out = *in + if in.Error != nil { + in, out := &in.Error, &out.Error + *out = new(DeleteFleetError) + (*in).DeepCopyInto(*out) + } + if in.FleetID != nil { + in, out := &in.FleetID, &out.FleetID + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeleteFleetErrorItem. +func (in *DeleteFleetErrorItem) DeepCopy() *DeleteFleetErrorItem { + if in == nil { + return nil + } + out := new(DeleteFleetErrorItem) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeleteFleetSuccessItem) DeepCopyInto(out *DeleteFleetSuccessItem) { + *out = *in + if in.CurrentFleetState != nil { + in, out := &in.CurrentFleetState, &out.CurrentFleetState + *out = new(string) + **out = **in + } + if in.FleetID != nil { + in, out := &in.FleetID, &out.FleetID + *out = new(string) + **out = **in + } + if in.PreviousFleetState != nil { + in, out := &in.PreviousFleetState, &out.PreviousFleetState + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeleteFleetSuccessItem. +func (in *DeleteFleetSuccessItem) DeepCopy() *DeleteFleetSuccessItem { + if in == nil { + return nil + } + out := new(DeleteFleetSuccessItem) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DeleteLaunchTemplateVersionsResponseErrorItem) DeepCopyInto(out *DeleteLaunchTemplateVersionsResponseErrorItem) { *out = *in @@ -5444,6 +5580,16 @@ func (in *DescribeFleetError) DeepCopyInto(out *DescribeFleetError) { *out = new(string) **out = **in } + if in.LaunchTemplateAndOverrides != nil { + in, out := &in.LaunchTemplateAndOverrides, &out.LaunchTemplateAndOverrides + *out = new(LaunchTemplateAndOverridesResponse) + (*in).DeepCopyInto(*out) + } + if in.Lifecycle != nil { + in, out := &in.Lifecycle, &out.Lifecycle + *out = new(string) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DescribeFleetError. @@ -5459,11 +5605,32 @@ func (in *DescribeFleetError) DeepCopy() *DescribeFleetError { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DescribeFleetsInstances) DeepCopyInto(out *DescribeFleetsInstances) { *out = *in + if in.InstanceIDs != nil { + in, out := &in.InstanceIDs, &out.InstanceIDs + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } if in.InstanceType != nil { in, out := &in.InstanceType, &out.InstanceType *out = new(string) **out = **in } + if in.LaunchTemplateAndOverrides != nil { + in, out := &in.LaunchTemplateAndOverrides, &out.LaunchTemplateAndOverrides + *out = new(LaunchTemplateAndOverridesResponse) + (*in).DeepCopyInto(*out) + } + if in.Lifecycle != nil { + in, out := &in.Lifecycle, &out.Lifecycle + *out = new(string) + **out = **in + } if in.Platform != nil { in, out := &in.Platform, &out.Platform *out = new(string) @@ -7549,6 +7716,33 @@ func (in *FirewallStatelessRule) DeepCopy() *FirewallStatelessRule { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Fleet) DeepCopyInto(out *Fleet) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Fleet. +func (in *Fleet) DeepCopy() *Fleet { + if in == nil { + return nil + } + out := new(Fleet) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Fleet) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FleetBlockDeviceMappingRequest) DeepCopyInto(out *FleetBlockDeviceMappingRequest) { *out = *in @@ -7557,6 +7751,11 @@ func (in *FleetBlockDeviceMappingRequest) DeepCopyInto(out *FleetBlockDeviceMapp *out = new(string) **out = **in } + if in.EBS != nil { + in, out := &in.EBS, &out.EBS + *out = new(FleetEBSBlockDeviceRequest) + (*in).DeepCopyInto(*out) + } if in.NoDevice != nil { in, out := &in.NoDevice, &out.NoDevice *out = new(string) @@ -7641,6 +7840,11 @@ func (in *FleetCapacityReservation) DeepCopy() *FleetCapacityReservation { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FleetData) DeepCopyInto(out *FleetData) { *out = *in + if in.ActivityStatus != nil { + in, out := &in.ActivityStatus, &out.ActivityStatus + *out = new(string) + **out = **in + } if in.ClientToken != nil { in, out := &in.ClientToken, &out.ClientToken *out = new(string) @@ -7655,6 +7859,32 @@ func (in *FleetData) DeepCopyInto(out *FleetData) { in, out := &in.CreateTime, &out.CreateTime *out = (*in).DeepCopy() } + if in.Errors != nil { + in, out := &in.Errors, &out.Errors + *out = make([]*DescribeFleetError, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(DescribeFleetError) + (*in).DeepCopyInto(*out) + } + } + } + if in.ExcessCapacityTerminationPolicy != nil { + in, out := &in.ExcessCapacityTerminationPolicy, &out.ExcessCapacityTerminationPolicy + *out = new(string) + **out = **in + } + if in.FleetID != nil { + in, out := &in.FleetID, &out.FleetID + *out = new(string) + **out = **in + } + if in.FleetState != nil { + in, out := &in.FleetState, &out.FleetState + *out = new(string) + **out = **in + } if in.FulfilledCapacity != nil { in, out := &in.FulfilledCapacity, &out.FulfilledCapacity *out = new(float64) @@ -7665,11 +7895,43 @@ func (in *FleetData) DeepCopyInto(out *FleetData) { *out = new(float64) **out = **in } + if in.Instances != nil { + in, out := &in.Instances, &out.Instances + *out = make([]*DescribeFleetsInstances, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(DescribeFleetsInstances) + (*in).DeepCopyInto(*out) + } + } + } + if in.LaunchTemplateConfigs != nil { + in, out := &in.LaunchTemplateConfigs, &out.LaunchTemplateConfigs + *out = make([]*FleetLaunchTemplateConfig, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(FleetLaunchTemplateConfig) + (*in).DeepCopyInto(*out) + } + } + } + if in.OnDemandOptions != nil { + in, out := &in.OnDemandOptions, &out.OnDemandOptions + *out = new(OnDemandOptions) + (*in).DeepCopyInto(*out) + } if in.ReplaceUnhealthyInstances != nil { in, out := &in.ReplaceUnhealthyInstances, &out.ReplaceUnhealthyInstances *out = new(bool) **out = **in } + if in.SpotOptions != nil { + in, out := &in.SpotOptions, &out.SpotOptions + *out = new(SpotOptions) + (*in).DeepCopyInto(*out) + } if in.Tags != nil { in, out := &in.Tags, &out.Tags *out = make([]*Tag, len(*in)) @@ -7681,11 +7943,21 @@ func (in *FleetData) DeepCopyInto(out *FleetData) { } } } + if in.TargetCapacitySpecification != nil { + in, out := &in.TargetCapacitySpecification, &out.TargetCapacitySpecification + *out = new(TargetCapacitySpecification) + (*in).DeepCopyInto(*out) + } if in.TerminateInstancesWithExpiration != nil { in, out := &in.TerminateInstancesWithExpiration, &out.TerminateInstancesWithExpiration *out = new(bool) **out = **in } + if in.Type != nil { + in, out := &in.Type, &out.Type + *out = new(string) + **out = **in + } if in.ValidFrom != nil { in, out := &in.ValidFrom, &out.ValidFrom *out = (*in).DeepCopy() @@ -7761,6 +8033,68 @@ func (in *FleetEBSBlockDeviceRequest) DeepCopy() *FleetEBSBlockDeviceRequest { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FleetLaunchTemplateConfig) DeepCopyInto(out *FleetLaunchTemplateConfig) { + *out = *in + if in.LaunchTemplateSpecification != nil { + in, out := &in.LaunchTemplateSpecification, &out.LaunchTemplateSpecification + *out = new(FleetLaunchTemplateSpecification) + (*in).DeepCopyInto(*out) + } + if in.Overrides != nil { + in, out := &in.Overrides, &out.Overrides + *out = make([]*FleetLaunchTemplateOverrides, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(FleetLaunchTemplateOverrides) + (*in).DeepCopyInto(*out) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetLaunchTemplateConfig. +func (in *FleetLaunchTemplateConfig) DeepCopy() *FleetLaunchTemplateConfig { + if in == nil { + return nil + } + out := new(FleetLaunchTemplateConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FleetLaunchTemplateConfigRequest) DeepCopyInto(out *FleetLaunchTemplateConfigRequest) { + *out = *in + if in.LaunchTemplateSpecification != nil { + in, out := &in.LaunchTemplateSpecification, &out.LaunchTemplateSpecification + *out = new(FleetLaunchTemplateSpecificationRequest) + (*in).DeepCopyInto(*out) + } + if in.Overrides != nil { + in, out := &in.Overrides, &out.Overrides + *out = make([]*FleetLaunchTemplateOverridesRequest, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(FleetLaunchTemplateOverridesRequest) + (*in).DeepCopyInto(*out) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetLaunchTemplateConfigRequest. +func (in *FleetLaunchTemplateConfigRequest) DeepCopy() *FleetLaunchTemplateConfigRequest { + if in == nil { + return nil + } + out := new(FleetLaunchTemplateConfigRequest) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FleetLaunchTemplateOverrides) DeepCopyInto(out *FleetLaunchTemplateOverrides) { *out = *in @@ -7769,11 +8103,88 @@ func (in *FleetLaunchTemplateOverrides) DeepCopyInto(out *FleetLaunchTemplateOve *out = new(string) **out = **in } - if in.AvailabilityZoneID != nil { - in, out := &in.AvailabilityZoneID, &out.AvailabilityZoneID + if in.BlockDeviceMappings != nil { + in, out := &in.BlockDeviceMappings, &out.BlockDeviceMappings + *out = make([]*BlockDeviceMappingResponse, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(BlockDeviceMappingResponse) + (*in).DeepCopyInto(*out) + } + } + } + if in.ImageID != nil { + in, out := &in.ImageID, &out.ImageID + *out = new(string) + **out = **in + } + if in.InstanceRequirements != nil { + in, out := &in.InstanceRequirements, &out.InstanceRequirements + *out = new(InstanceRequirements) + (*in).DeepCopyInto(*out) + } + if in.InstanceType != nil { + in, out := &in.InstanceType, &out.InstanceType *out = new(string) **out = **in } + if in.MaxPrice != nil { + in, out := &in.MaxPrice, &out.MaxPrice + *out = new(string) + **out = **in + } + if in.Placement != nil { + in, out := &in.Placement, &out.Placement + *out = new(PlacementResponse) + (*in).DeepCopyInto(*out) + } + if in.Priority != nil { + in, out := &in.Priority, &out.Priority + *out = new(float64) + **out = **in + } + if in.SubnetID != nil { + in, out := &in.SubnetID, &out.SubnetID + *out = new(string) + **out = **in + } + if in.WeightedCapacity != nil { + in, out := &in.WeightedCapacity, &out.WeightedCapacity + *out = new(float64) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetLaunchTemplateOverrides. +func (in *FleetLaunchTemplateOverrides) DeepCopy() *FleetLaunchTemplateOverrides { + if in == nil { + return nil + } + out := new(FleetLaunchTemplateOverrides) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FleetLaunchTemplateOverridesRequest) DeepCopyInto(out *FleetLaunchTemplateOverridesRequest) { + *out = *in + if in.AvailabilityZone != nil { + in, out := &in.AvailabilityZone, &out.AvailabilityZone + *out = new(string) + **out = **in + } + if in.BlockDeviceMappings != nil { + in, out := &in.BlockDeviceMappings, &out.BlockDeviceMappings + *out = make([]*FleetBlockDeviceMappingRequest, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(FleetBlockDeviceMappingRequest) + (*in).DeepCopyInto(*out) + } + } + } if in.ImageID != nil { in, out := &in.ImageID, &out.ImageID *out = new(string) @@ -7781,7 +8192,7 @@ func (in *FleetLaunchTemplateOverrides) DeepCopyInto(out *FleetLaunchTemplateOve } if in.InstanceRequirements != nil { in, out := &in.InstanceRequirements, &out.InstanceRequirements - *out = new(InstanceRequirements) + *out = new(InstanceRequirementsRequest) (*in).DeepCopyInto(*out) } if in.InstanceType != nil { @@ -7794,194 +8205,368 @@ func (in *FleetLaunchTemplateOverrides) DeepCopyInto(out *FleetLaunchTemplateOve *out = new(string) **out = **in } + if in.Placement != nil { + in, out := &in.Placement, &out.Placement + *out = new(Placement) + (*in).DeepCopyInto(*out) + } if in.Priority != nil { in, out := &in.Priority, &out.Priority *out = new(float64) **out = **in } - if in.SubnetID != nil { - in, out := &in.SubnetID, &out.SubnetID + if in.SubnetID != nil { + in, out := &in.SubnetID, &out.SubnetID + *out = new(string) + **out = **in + } + if in.WeightedCapacity != nil { + in, out := &in.WeightedCapacity, &out.WeightedCapacity + *out = new(float64) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetLaunchTemplateOverridesRequest. +func (in *FleetLaunchTemplateOverridesRequest) DeepCopy() *FleetLaunchTemplateOverridesRequest { + if in == nil { + return nil + } + out := new(FleetLaunchTemplateOverridesRequest) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FleetLaunchTemplateSpecification) DeepCopyInto(out *FleetLaunchTemplateSpecification) { + *out = *in + if in.LaunchTemplateID != nil { + in, out := &in.LaunchTemplateID, &out.LaunchTemplateID + *out = new(string) + **out = **in + } + if in.LaunchTemplateName != nil { + in, out := &in.LaunchTemplateName, &out.LaunchTemplateName + *out = new(string) + **out = **in + } + if in.Version != nil { + in, out := &in.Version, &out.Version + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetLaunchTemplateSpecification. +func (in *FleetLaunchTemplateSpecification) DeepCopy() *FleetLaunchTemplateSpecification { + if in == nil { + return nil + } + out := new(FleetLaunchTemplateSpecification) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FleetLaunchTemplateSpecificationRequest) DeepCopyInto(out *FleetLaunchTemplateSpecificationRequest) { + *out = *in + if in.LaunchTemplateID != nil { + in, out := &in.LaunchTemplateID, &out.LaunchTemplateID + *out = new(string) + **out = **in + } + if in.LaunchTemplateName != nil { + in, out := &in.LaunchTemplateName, &out.LaunchTemplateName + *out = new(string) + **out = **in + } + if in.Version != nil { + in, out := &in.Version, &out.Version + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetLaunchTemplateSpecificationRequest. +func (in *FleetLaunchTemplateSpecificationRequest) DeepCopy() *FleetLaunchTemplateSpecificationRequest { + if in == nil { + return nil + } + out := new(FleetLaunchTemplateSpecificationRequest) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FleetList) DeepCopyInto(out *FleetList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Fleet, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetList. +func (in *FleetList) DeepCopy() *FleetList { + if in == nil { + return nil + } + out := new(FleetList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FleetList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FleetSpec) DeepCopyInto(out *FleetSpec) { + *out = *in + if in.Context != nil { + in, out := &in.Context, &out.Context + *out = new(string) + **out = **in + } + if in.ExcessCapacityTerminationPolicy != nil { + in, out := &in.ExcessCapacityTerminationPolicy, &out.ExcessCapacityTerminationPolicy + *out = new(string) + **out = **in + } + if in.LaunchTemplateConfigs != nil { + in, out := &in.LaunchTemplateConfigs, &out.LaunchTemplateConfigs + *out = make([]*FleetLaunchTemplateConfigRequest, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(FleetLaunchTemplateConfigRequest) + (*in).DeepCopyInto(*out) + } + } + } + if in.OnDemandOptions != nil { + in, out := &in.OnDemandOptions, &out.OnDemandOptions + *out = new(OnDemandOptionsRequest) + (*in).DeepCopyInto(*out) + } + if in.ReplaceUnhealthyInstances != nil { + in, out := &in.ReplaceUnhealthyInstances, &out.ReplaceUnhealthyInstances + *out = new(bool) + **out = **in + } + if in.SpotOptions != nil { + in, out := &in.SpotOptions, &out.SpotOptions + *out = new(SpotOptionsRequest) + (*in).DeepCopyInto(*out) + } + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]*Tag, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Tag) + (*in).DeepCopyInto(*out) + } + } + } + if in.TargetCapacitySpecification != nil { + in, out := &in.TargetCapacitySpecification, &out.TargetCapacitySpecification + *out = new(TargetCapacitySpecificationRequest) + (*in).DeepCopyInto(*out) + } + if in.TerminateInstancesOnDeletion != nil { + in, out := &in.TerminateInstancesOnDeletion, &out.TerminateInstancesOnDeletion + *out = new(bool) + **out = **in + } + if in.TerminateInstancesWithExpiration != nil { + in, out := &in.TerminateInstancesWithExpiration, &out.TerminateInstancesWithExpiration + *out = new(bool) + **out = **in + } + if in.Type != nil { + in, out := &in.Type, &out.Type *out = new(string) **out = **in } - if in.WeightedCapacity != nil { - in, out := &in.WeightedCapacity, &out.WeightedCapacity - *out = new(float64) - **out = **in + if in.ValidFrom != nil { + in, out := &in.ValidFrom, &out.ValidFrom + *out = (*in).DeepCopy() + } + if in.ValidUntil != nil { + in, out := &in.ValidUntil, &out.ValidUntil + *out = (*in).DeepCopy() } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetLaunchTemplateOverrides. -func (in *FleetLaunchTemplateOverrides) DeepCopy() *FleetLaunchTemplateOverrides { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetSpec. +func (in *FleetSpec) DeepCopy() *FleetSpec { if in == nil { return nil } - out := new(FleetLaunchTemplateOverrides) + out := new(FleetSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetLaunchTemplateOverridesRequest) DeepCopyInto(out *FleetLaunchTemplateOverridesRequest) { +func (in *FleetSpotCapacityRebalance) DeepCopyInto(out *FleetSpotCapacityRebalance) { *out = *in - if in.AvailabilityZone != nil { - in, out := &in.AvailabilityZone, &out.AvailabilityZone - *out = new(string) - **out = **in - } - if in.AvailabilityZoneID != nil { - in, out := &in.AvailabilityZoneID, &out.AvailabilityZoneID - *out = new(string) - **out = **in - } - if in.ImageID != nil { - in, out := &in.ImageID, &out.ImageID - *out = new(string) - **out = **in - } - if in.InstanceRequirements != nil { - in, out := &in.InstanceRequirements, &out.InstanceRequirements - *out = new(InstanceRequirementsRequest) - (*in).DeepCopyInto(*out) - } - if in.InstanceType != nil { - in, out := &in.InstanceType, &out.InstanceType - *out = new(string) - **out = **in - } - if in.MaxPrice != nil { - in, out := &in.MaxPrice, &out.MaxPrice - *out = new(string) - **out = **in - } - if in.Placement != nil { - in, out := &in.Placement, &out.Placement - *out = new(Placement) - (*in).DeepCopyInto(*out) - } - if in.Priority != nil { - in, out := &in.Priority, &out.Priority - *out = new(float64) - **out = **in - } - if in.SubnetID != nil { - in, out := &in.SubnetID, &out.SubnetID + if in.ReplacementStrategy != nil { + in, out := &in.ReplacementStrategy, &out.ReplacementStrategy *out = new(string) **out = **in } - if in.WeightedCapacity != nil { - in, out := &in.WeightedCapacity, &out.WeightedCapacity - *out = new(float64) + if in.TerminationDelay != nil { + in, out := &in.TerminationDelay, &out.TerminationDelay + *out = new(int64) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetLaunchTemplateOverridesRequest. -func (in *FleetLaunchTemplateOverridesRequest) DeepCopy() *FleetLaunchTemplateOverridesRequest { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetSpotCapacityRebalance. +func (in *FleetSpotCapacityRebalance) DeepCopy() *FleetSpotCapacityRebalance { if in == nil { return nil } - out := new(FleetLaunchTemplateOverridesRequest) + out := new(FleetSpotCapacityRebalance) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetLaunchTemplateSpecification) DeepCopyInto(out *FleetLaunchTemplateSpecification) { +func (in *FleetSpotCapacityRebalanceRequest) DeepCopyInto(out *FleetSpotCapacityRebalanceRequest) { *out = *in - if in.LaunchTemplateID != nil { - in, out := &in.LaunchTemplateID, &out.LaunchTemplateID - *out = new(string) - **out = **in - } - if in.LaunchTemplateName != nil { - in, out := &in.LaunchTemplateName, &out.LaunchTemplateName + if in.ReplacementStrategy != nil { + in, out := &in.ReplacementStrategy, &out.ReplacementStrategy *out = new(string) **out = **in } - if in.Version != nil { - in, out := &in.Version, &out.Version - *out = new(string) + if in.TerminationDelay != nil { + in, out := &in.TerminationDelay, &out.TerminationDelay + *out = new(int64) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetLaunchTemplateSpecification. -func (in *FleetLaunchTemplateSpecification) DeepCopy() *FleetLaunchTemplateSpecification { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetSpotCapacityRebalanceRequest. +func (in *FleetSpotCapacityRebalanceRequest) DeepCopy() *FleetSpotCapacityRebalanceRequest { if in == nil { return nil } - out := new(FleetLaunchTemplateSpecification) + out := new(FleetSpotCapacityRebalanceRequest) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetLaunchTemplateSpecificationRequest) DeepCopyInto(out *FleetLaunchTemplateSpecificationRequest) { +func (in *FleetSpotMaintenanceStrategies) DeepCopyInto(out *FleetSpotMaintenanceStrategies) { *out = *in - if in.LaunchTemplateID != nil { - in, out := &in.LaunchTemplateID, &out.LaunchTemplateID - *out = new(string) - **out = **in - } - if in.LaunchTemplateName != nil { - in, out := &in.LaunchTemplateName, &out.LaunchTemplateName - *out = new(string) - **out = **in - } - if in.Version != nil { - in, out := &in.Version, &out.Version - *out = new(string) - **out = **in + if in.CapacityRebalance != nil { + in, out := &in.CapacityRebalance, &out.CapacityRebalance + *out = new(FleetSpotCapacityRebalance) + (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetLaunchTemplateSpecificationRequest. -func (in *FleetLaunchTemplateSpecificationRequest) DeepCopy() *FleetLaunchTemplateSpecificationRequest { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetSpotMaintenanceStrategies. +func (in *FleetSpotMaintenanceStrategies) DeepCopy() *FleetSpotMaintenanceStrategies { if in == nil { return nil } - out := new(FleetLaunchTemplateSpecificationRequest) + out := new(FleetSpotMaintenanceStrategies) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetSpotCapacityRebalance) DeepCopyInto(out *FleetSpotCapacityRebalance) { +func (in *FleetSpotMaintenanceStrategiesRequest) DeepCopyInto(out *FleetSpotMaintenanceStrategiesRequest) { *out = *in - if in.TerminationDelay != nil { - in, out := &in.TerminationDelay, &out.TerminationDelay - *out = new(int64) - **out = **in + if in.CapacityRebalance != nil { + in, out := &in.CapacityRebalance, &out.CapacityRebalance + *out = new(FleetSpotCapacityRebalanceRequest) + (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetSpotCapacityRebalance. -func (in *FleetSpotCapacityRebalance) DeepCopy() *FleetSpotCapacityRebalance { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetSpotMaintenanceStrategiesRequest. +func (in *FleetSpotMaintenanceStrategiesRequest) DeepCopy() *FleetSpotMaintenanceStrategiesRequest { if in == nil { return nil } - out := new(FleetSpotCapacityRebalance) + out := new(FleetSpotMaintenanceStrategiesRequest) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FleetSpotCapacityRebalanceRequest) DeepCopyInto(out *FleetSpotCapacityRebalanceRequest) { +func (in *FleetStatus) DeepCopyInto(out *FleetStatus) { *out = *in - if in.TerminationDelay != nil { - in, out := &in.TerminationDelay, &out.TerminationDelay - *out = new(int64) + if in.ACKResourceMetadata != nil { + in, out := &in.ACKResourceMetadata, &out.ACKResourceMetadata + *out = new(corev1alpha1.ResourceMetadata) + (*in).DeepCopyInto(*out) + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]*corev1alpha1.Condition, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(corev1alpha1.Condition) + (*in).DeepCopyInto(*out) + } + } + } + if in.ActivityStatus != nil { + in, out := &in.ActivityStatus, &out.ActivityStatus + *out = new(string) + **out = **in + } + if in.Errors != nil { + in, out := &in.Errors, &out.Errors + *out = make([]*CreateFleetError, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(CreateFleetError) + (*in).DeepCopyInto(*out) + } + } + } + if in.FleetID != nil { + in, out := &in.FleetID, &out.FleetID + *out = new(string) + **out = **in + } + if in.FleetState != nil { + in, out := &in.FleetState, &out.FleetState + *out = new(string) + **out = **in + } + if in.FulfilledCapacity != nil { + in, out := &in.FulfilledCapacity, &out.FulfilledCapacity + *out = new(float64) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetSpotCapacityRebalanceRequest. -func (in *FleetSpotCapacityRebalanceRequest) DeepCopy() *FleetSpotCapacityRebalanceRequest { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FleetStatus. +func (in *FleetStatus) DeepCopy() *FleetStatus { if in == nil { return nil } - out := new(FleetSpotCapacityRebalanceRequest) + out := new(FleetStatus) in.DeepCopyInto(out) return out } @@ -14616,6 +15201,31 @@ func (in *LaunchTemplate) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LaunchTemplateAndOverridesResponse) DeepCopyInto(out *LaunchTemplateAndOverridesResponse) { + *out = *in + if in.LaunchTemplateSpecification != nil { + in, out := &in.LaunchTemplateSpecification, &out.LaunchTemplateSpecification + *out = new(FleetLaunchTemplateSpecification) + (*in).DeepCopyInto(*out) + } + if in.Overrides != nil { + in, out := &in.Overrides, &out.Overrides + *out = new(FleetLaunchTemplateOverrides) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LaunchTemplateAndOverridesResponse. +func (in *LaunchTemplateAndOverridesResponse) DeepCopy() *LaunchTemplateAndOverridesResponse { + if in == nil { + return nil + } + out := new(LaunchTemplateAndOverridesResponse) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LaunchTemplateBlockDeviceMapping) DeepCopyInto(out *LaunchTemplateBlockDeviceMapping) { *out = *in @@ -14796,6 +15406,26 @@ func (in *LaunchTemplateCapacityReservationSpecificationResponse) DeepCopy() *La return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LaunchTemplateConfig) DeepCopyInto(out *LaunchTemplateConfig) { + *out = *in + if in.LaunchTemplateSpecification != nil { + in, out := &in.LaunchTemplateSpecification, &out.LaunchTemplateSpecification + *out = new(FleetLaunchTemplateSpecification) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LaunchTemplateConfig. +func (in *LaunchTemplateConfig) DeepCopy() *LaunchTemplateConfig { + if in == nil { + return nil + } + out := new(LaunchTemplateConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LaunchTemplateEBSBlockDevice) DeepCopyInto(out *LaunchTemplateEBSBlockDevice) { *out = *in @@ -19247,6 +19877,16 @@ func (in *OIDCOptions) DeepCopy() *OIDCOptions { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OnDemandOptions) DeepCopyInto(out *OnDemandOptions) { *out = *in + if in.AllocationStrategy != nil { + in, out := &in.AllocationStrategy, &out.AllocationStrategy + *out = new(string) + **out = **in + } + if in.CapacityReservationOptions != nil { + in, out := &in.CapacityReservationOptions, &out.CapacityReservationOptions + *out = new(CapacityReservationOptions) + (*in).DeepCopyInto(*out) + } if in.MaxTotalPrice != nil { in, out := &in.MaxTotalPrice, &out.MaxTotalPrice *out = new(string) @@ -19282,6 +19922,16 @@ func (in *OnDemandOptions) DeepCopy() *OnDemandOptions { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OnDemandOptionsRequest) DeepCopyInto(out *OnDemandOptionsRequest) { *out = *in + if in.AllocationStrategy != nil { + in, out := &in.AllocationStrategy, &out.AllocationStrategy + *out = new(string) + **out = **in + } + if in.CapacityReservationOptions != nil { + in, out := &in.CapacityReservationOptions, &out.CapacityReservationOptions + *out = new(CapacityReservationOptionsRequest) + (*in).DeepCopyInto(*out) + } if in.MaxTotalPrice != nil { in, out := &in.MaxTotalPrice, &out.MaxTotalPrice *out = new(string) @@ -25223,11 +25873,21 @@ func (in *SpotFleetRequestConfigData) DeepCopyInto(out *SpotFleetRequestConfigDa *out = new(int64) **out = **in } + if in.TargetCapacityUnitType != nil { + in, out := &in.TargetCapacityUnitType, &out.TargetCapacityUnitType + *out = new(string) + **out = **in + } if in.TerminateInstancesWithExpiration != nil { in, out := &in.TerminateInstancesWithExpiration, &out.TerminateInstancesWithExpiration *out = new(bool) **out = **in } + if in.Type != nil { + in, out := &in.Type, &out.Type + *out = new(string) + **out = **in + } if in.ValidFrom != nil { in, out := &in.ValidFrom, &out.ValidFrom *out = (*in).DeepCopy() @@ -25468,11 +26128,26 @@ func (in *SpotMarketOptions) DeepCopy() *SpotMarketOptions { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SpotOptions) DeepCopyInto(out *SpotOptions) { *out = *in + if in.AllocationStrategy != nil { + in, out := &in.AllocationStrategy, &out.AllocationStrategy + *out = new(string) + **out = **in + } + if in.InstanceInterruptionBehavior != nil { + in, out := &in.InstanceInterruptionBehavior, &out.InstanceInterruptionBehavior + *out = new(string) + **out = **in + } if in.InstancePoolsToUseCount != nil { in, out := &in.InstancePoolsToUseCount, &out.InstancePoolsToUseCount *out = new(int64) **out = **in } + if in.MaintenanceStrategies != nil { + in, out := &in.MaintenanceStrategies, &out.MaintenanceStrategies + *out = new(FleetSpotMaintenanceStrategies) + (*in).DeepCopyInto(*out) + } if in.MaxTotalPrice != nil { in, out := &in.MaxTotalPrice, &out.MaxTotalPrice *out = new(string) @@ -25508,11 +26183,26 @@ func (in *SpotOptions) DeepCopy() *SpotOptions { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SpotOptionsRequest) DeepCopyInto(out *SpotOptionsRequest) { *out = *in + if in.AllocationStrategy != nil { + in, out := &in.AllocationStrategy, &out.AllocationStrategy + *out = new(string) + **out = **in + } + if in.InstanceInterruptionBehavior != nil { + in, out := &in.InstanceInterruptionBehavior, &out.InstanceInterruptionBehavior + *out = new(string) + **out = **in + } if in.InstancePoolsToUseCount != nil { in, out := &in.InstancePoolsToUseCount, &out.InstancePoolsToUseCount *out = new(int64) **out = **in } + if in.MaintenanceStrategies != nil { + in, out := &in.MaintenanceStrategies, &out.MaintenanceStrategies + *out = new(FleetSpotMaintenanceStrategiesRequest) + (*in).DeepCopyInto(*out) + } if in.MaxTotalPrice != nil { in, out := &in.MaxTotalPrice, &out.MaxTotalPrice *out = new(string) @@ -26575,6 +27265,11 @@ func (in *TagSpecification) DeepCopy() *TagSpecification { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TargetCapacitySpecification) DeepCopyInto(out *TargetCapacitySpecification) { *out = *in + if in.DefaultTargetCapacityType != nil { + in, out := &in.DefaultTargetCapacityType, &out.DefaultTargetCapacityType + *out = new(string) + **out = **in + } if in.OnDemandTargetCapacity != nil { in, out := &in.OnDemandTargetCapacity, &out.OnDemandTargetCapacity *out = new(int64) @@ -26585,6 +27280,11 @@ func (in *TargetCapacitySpecification) DeepCopyInto(out *TargetCapacitySpecifica *out = new(int64) **out = **in } + if in.TargetCapacityUnitType != nil { + in, out := &in.TargetCapacityUnitType, &out.TargetCapacityUnitType + *out = new(string) + **out = **in + } if in.TotalTargetCapacity != nil { in, out := &in.TotalTargetCapacity, &out.TotalTargetCapacity *out = new(int64) @@ -26605,6 +27305,11 @@ func (in *TargetCapacitySpecification) DeepCopy() *TargetCapacitySpecification { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TargetCapacitySpecificationRequest) DeepCopyInto(out *TargetCapacitySpecificationRequest) { *out = *in + if in.DefaultTargetCapacityType != nil { + in, out := &in.DefaultTargetCapacityType, &out.DefaultTargetCapacityType + *out = new(string) + **out = **in + } if in.OnDemandTargetCapacity != nil { in, out := &in.OnDemandTargetCapacity, &out.OnDemandTargetCapacity *out = new(int64) @@ -26615,6 +27320,11 @@ func (in *TargetCapacitySpecificationRequest) DeepCopyInto(out *TargetCapacitySp *out = new(int64) **out = **in } + if in.TargetCapacityUnitType != nil { + in, out := &in.TargetCapacityUnitType, &out.TargetCapacityUnitType + *out = new(string) + **out = **in + } if in.TotalTargetCapacity != nil { in, out := &in.TotalTargetCapacity, &out.TotalTargetCapacity *out = new(int64) diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 009f2f5f..e98b3ef4 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -43,6 +43,7 @@ import ( _ "github.com/aws-controllers-k8s/ec2-controller/pkg/resource/capacity_reservation" _ "github.com/aws-controllers-k8s/ec2-controller/pkg/resource/dhcp_options" _ "github.com/aws-controllers-k8s/ec2-controller/pkg/resource/elastic_ip_address" + _ "github.com/aws-controllers-k8s/ec2-controller/pkg/resource/fleet" _ "github.com/aws-controllers-k8s/ec2-controller/pkg/resource/flow_log" _ "github.com/aws-controllers-k8s/ec2-controller/pkg/resource/instance" _ "github.com/aws-controllers-k8s/ec2-controller/pkg/resource/internet_gateway" diff --git a/config/crd/bases/ec2.services.k8s.aws_fleets.yaml b/config/crd/bases/ec2.services.k8s.aws_fleets.yaml new file mode 100644 index 00000000..11ea8ce0 --- /dev/null +++ b/config/crd/bases/ec2.services.k8s.aws_fleets.yaml @@ -0,0 +1,994 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + name: fleets.ec2.services.k8s.aws +spec: + group: ec2.services.k8s.aws + names: + kind: Fleet + listKind: FleetList + plural: fleets + singular: fleet + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.fleetID + name: ID + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Fleet is the Schema for the Fleets API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: FleetSpec defines the desired state of Fleet. + properties: + context: + description: Reserved. + type: string + excessCapacityTerminationPolicy: + description: |- + Indicates whether running instances should be terminated if the total target + capacity of the EC2 Fleet is decreased below the current size of the EC2 + Fleet. + + Supported only for fleets of type maintain. + type: string + launchTemplateConfigs: + description: The configuration for the EC2 Fleet. + items: + description: Describes a launch template and overrides. + properties: + launchTemplateSpecification: + description: |- + The Amazon EC2 launch template that can be used by an EC2 Fleet to configure + Amazon EC2 instances. You must specify either the ID or name of the launch + template in the request, but not both. + + For information about launch templates, see Launch an instance from a launch + template (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-templates.html) + in the Amazon EC2 User Guide. + properties: + launchTemplateID: + type: string + launchTemplateName: + type: string + version: + type: string + type: object + overrides: + items: + description: Describes overrides for a launch template. + properties: + availabilityZone: + type: string + blockDeviceMappings: + items: + description: |- + Describes a block device mapping, which defines the EBS volumes and instance + store volumes to attach to an instance at launch. + + To override a block device mapping specified in the launch template: + + * Specify the exact same DeviceName here as specified in the launch template. + + * Only specify the parameters you want to change. + + * Any parameters you don't specify here will keep their original launch + template values. + + To add a new block device mapping: + + * Specify a DeviceName that doesn't exist in the launch template. + + * Specify all desired parameters here. + properties: + deviceName: + type: string + ebs: + description: Describes a block device for an EBS + volume. + properties: + deleteOnTermination: + type: boolean + encrypted: + type: boolean + iops: + format: int64 + type: integer + kmsKeyID: + type: string + snapshotID: + type: string + throughput: + format: int64 + type: integer + volumeSize: + format: int64 + type: integer + volumeType: + type: string + type: object + noDevice: + type: string + virtualName: + type: string + type: object + type: array + imageID: + type: string + instanceRequirements: + description: |- + The attributes for the instance types. When you specify instance attributes, + Amazon EC2 will identify instance types with these attributes. + + You must specify VCpuCount and MemoryMiB. All other attributes are optional. + Any unspecified optional attribute is set to its default. + + When you specify multiple attributes, you get instance types that satisfy + all of the specified attributes. If you specify multiple values for an attribute, + you get instance types that satisfy any of the specified values. + + To limit the list of instance types from which Amazon EC2 can identify matching + instance types, you can use one of the following parameters, but not both + in the same request: + + * AllowedInstanceTypes - The instance types to include in the list. All + other instance types are ignored, even if they match your specified attributes. + + * ExcludedInstanceTypes - The instance types to exclude from the list, + even if they match your specified attributes. + + If you specify InstanceRequirements, you can't specify InstanceType. + + Attribute-based instance type selection is only supported when using Auto + Scaling groups, EC2 Fleet, and Spot Fleet to launch instances. If you plan + to use the launch template in the launch instance wizard (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-instance-wizard.html), + or with the RunInstances (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html) + API or AWS::EC2::Instance (https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html) + Amazon Web Services CloudFormation resource, you can't specify InstanceRequirements. + + For more information, see Specify attributes for instance type selection + for EC2 Fleet or Spot Fleet (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-attribute-based-instance-type-selection.html) + and Spot placement score (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-placement-score.html) + in the Amazon EC2 User Guide. + properties: + acceleratorCount: + description: |- + The minimum and maximum number of accelerators (GPUs, FPGAs, or Amazon Web + Services Inferentia chips) on an instance. To exclude accelerator-enabled + instance types, set Max to 0. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + acceleratorManufacturers: + items: + type: string + type: array + acceleratorNames: + items: + type: string + type: array + acceleratorTotalMemoryMiB: + description: The minimum and maximum amount of total + accelerator memory, in MiB. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + acceleratorTypes: + items: + type: string + type: array + allowedInstanceTypes: + items: + type: string + type: array + bareMetal: + type: string + baselineEBSBandwidthMbps: + description: |- + The minimum and maximum baseline bandwidth to Amazon EBS, in Mbps. For more + information, see Amazon EBS–optimized instances (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-optimized.html) + in the Amazon EC2 User Guide. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + baselinePerformanceFactors: + description: |- + The baseline performance to consider, using an instance family as a baseline + reference. The instance family establishes the lowest acceptable level of + performance. Amazon EC2 uses this baseline to guide instance type selection, + but there is no guarantee that the selected instance types will always exceed + the baseline for every application. + + Currently, this parameter only supports CPU performance as a baseline performance + factor. For example, specifying c6i would use the CPU performance of the + c6i family as the baseline reference. + properties: + cpu: + description: |- + The CPU performance to consider, using an instance family as the baseline + reference. + properties: + references: + items: + description: |- + Specify an instance family to use as the baseline reference for CPU performance. + All instance types that match your specified attributes will be compared + against the CPU performance of the referenced instance family, regardless + of CPU manufacturer or architecture. + + Currently, only one instance family can be specified in the list. + properties: + instanceFamily: + type: string + type: object + type: array + type: object + type: object + burstablePerformance: + type: string + cpuManufacturers: + items: + type: string + type: array + excludedInstanceTypes: + items: + type: string + type: array + instanceGenerations: + items: + type: string + type: array + localStorage: + type: string + localStorageTypes: + items: + type: string + type: array + maxSpotPriceAsPercentageOfOptimalOnDemandPrice: + format: int64 + type: integer + memoryGiBPerVCPU: + description: The minimum and maximum amount of memory + per vCPU, in GiB. + properties: + max: + type: number + min: + type: number + type: object + memoryMiB: + description: The minimum and maximum amount of memory, + in MiB. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + networkBandwidthGbps: + description: |- + The minimum and maximum amount of network bandwidth, in gigabits per second + (Gbps). + + Setting the minimum bandwidth does not guarantee that your instance will + achieve the minimum bandwidth. Amazon EC2 will identify instance types that + support the specified minimum bandwidth, but the actual bandwidth of your + instance might go below the specified minimum at times. For more information, + see Available instance bandwidth (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-network-bandwidth.html#available-instance-bandwidth) + in the Amazon EC2 User Guide. + properties: + max: + type: number + min: + type: number + type: object + networkInterfaceCount: + description: The minimum and maximum number of network + interfaces. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + onDemandMaxPricePercentageOverLowestPrice: + format: int64 + type: integer + requireHibernateSupport: + type: boolean + spotMaxPricePercentageOverLowestPrice: + format: int64 + type: integer + totalLocalStorageGB: + description: The minimum and maximum amount of total + local storage, in GB. + properties: + max: + type: number + min: + type: number + type: object + vCPUCount: + description: The minimum and maximum number of vCPUs. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + type: object + instanceType: + type: string + maxPrice: + type: string + placement: + description: Describes the placement of an instance. + properties: + affinity: + type: string + availabilityZone: + type: string + groupName: + type: string + hostID: + type: string + hostResourceGroupARN: + type: string + partitionNumber: + format: int64 + type: integer + spreadDomain: + type: string + tenancy: + type: string + type: object + priority: + type: number + subnetID: + type: string + weightedCapacity: + type: number + type: object + type: array + type: object + type: array + onDemandOptions: + description: Describes the configuration of On-Demand Instances in + an EC2 Fleet. + properties: + allocationStrategy: + type: string + capacityReservationOptions: + description: |- + Describes the strategy for using unused Capacity Reservations for fulfilling + On-Demand capacity. + + This strategy can only be used if the EC2 Fleet is of type instant. + + For more information about Capacity Reservations, see On-Demand Capacity + Reservations (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-capacity-reservations.html) + in the Amazon EC2 User Guide. For examples of using Capacity Reservations + in an EC2 Fleet, see EC2 Fleet example configurations (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-examples.html) + in the Amazon EC2 User Guide. + properties: + usageStrategy: + type: string + type: object + maxTotalPrice: + type: string + minTargetCapacity: + format: int64 + type: integer + singleAvailabilityZone: + type: boolean + singleInstanceType: + type: boolean + type: object + x-kubernetes-validations: + - message: Value is immutable once set + rule: self == oldSelf + replaceUnhealthyInstances: + description: |- + Indicates whether EC2 Fleet should replace unhealthy Spot Instances. Supported + only for fleets of type maintain. For more information, see EC2 Fleet health + checks (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/manage-ec2-fleet.html#ec2-fleet-health-checks) + in the Amazon EC2 User Guide. + type: boolean + x-kubernetes-validations: + - message: Value is immutable once set + rule: self == oldSelf + spotOptions: + description: Describes the configuration of Spot Instances in an EC2 + Fleet. + properties: + allocationStrategy: + type: string + instanceInterruptionBehavior: + type: string + instancePoolsToUseCount: + format: int64 + type: integer + maintenanceStrategies: + description: |- + The strategies for managing your Spot Instances that are at an elevated risk + of being interrupted. + properties: + capacityRebalance: + description: |- + The Spot Instance replacement strategy to use when Amazon EC2 emits a rebalance + notification signal that your Spot Instance is at an elevated risk of being + interrupted. For more information, see Capacity rebalancing (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-capacity-rebalance.html) + in the Amazon EC2 User Guide. + properties: + replacementStrategy: + type: string + terminationDelay: + format: int64 + type: integer + type: object + type: object + maxTotalPrice: + type: string + minTargetCapacity: + format: int64 + type: integer + singleAvailabilityZone: + type: boolean + singleInstanceType: + type: boolean + type: object + x-kubernetes-validations: + - message: Value is immutable once set + rule: self == oldSelf + tags: + description: |- + The tags. The value parameter is required, but if you don't want the tag + to have a value, specify the parameter with no value, and we set the value + to an empty string. + items: + description: Describes a tag. + properties: + key: + type: string + value: + type: string + type: object + type: array + targetCapacitySpecification: + description: The number of units to request. + properties: + defaultTargetCapacityType: + type: string + x-kubernetes-validations: + - message: Value is immutable once set + rule: self == oldSelf + onDemandTargetCapacity: + format: int64 + type: integer + spotTargetCapacity: + format: int64 + type: integer + targetCapacityUnitType: + type: string + totalTargetCapacity: + format: int64 + type: integer + type: object + terminateInstancesOnDeletion: + type: boolean + terminateInstancesWithExpiration: + description: |- + Indicates whether running instances should be terminated when the EC2 Fleet + expires. + type: boolean + x-kubernetes-validations: + - message: Value is immutable once set + rule: self == oldSelf + type: + description: |- + The fleet type. The default value is maintain. + + * maintain - The EC2 Fleet places an asynchronous request for your desired + capacity, and continues to maintain your desired Spot capacity by replenishing + interrupted Spot Instances. + + * request - The EC2 Fleet places an asynchronous one-time request for + your desired capacity, but does submit Spot requests in alternative capacity + pools if Spot capacity is unavailable, and does not maintain Spot capacity + if Spot Instances are interrupted. + + * instant - The EC2 Fleet places a synchronous one-time request for your + desired capacity, and returns errors for any instances that could not + be launched. + + For more information, see EC2 Fleet request types (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-request-type.html) + in the Amazon EC2 User Guide. + type: string + x-kubernetes-validations: + - message: Value is immutable once set + rule: self == oldSelf + validFrom: + description: |- + The start date and time of the request, in UTC format (for example, YYYY-MM-DDTHH:MM:SSZ). + The default is to start fulfilling the request immediately. + format: date-time + type: string + x-kubernetes-validations: + - message: Value is immutable once set + rule: self == oldSelf + validUntil: + description: |- + The end date and time of the request, in UTC format (for example, YYYY-MM-DDTHH:MM:SSZ). + At this point, no new EC2 Fleet requests are placed or able to fulfill the + request. If no value is specified, the request remains until you cancel it. + format: date-time + type: string + x-kubernetes-validations: + - message: Value is immutable once set + rule: self == oldSelf + required: + - launchTemplateConfigs + - targetCapacitySpecification + type: object + status: + description: FleetStatus defines the observed state of Fleet + properties: + ackResourceMetadata: + description: |- + All CRs managed by ACK have a common `Status.ACKResourceMetadata` member + that is used to contain resource sync state, account ownership, + constructed ARN for the resource + properties: + arn: + description: |- + ARN is the Amazon Resource Name for the resource. This is a + globally-unique identifier and is set only by the ACK service controller + once the controller has orchestrated the creation of the resource OR + when it has verified that an "adopted" resource (a resource where the + ARN annotation was set by the Kubernetes user on the CR) exists and + matches the supplied CR's Spec field values. + https://github.com/aws/aws-controllers-k8s/issues/270 + type: string + ownerAccountID: + description: |- + OwnerAccountID is the AWS Account ID of the account that owns the + backend AWS service API resource. + type: string + region: + description: Region is the AWS region in which the resource exists + or will exist. + type: string + required: + - ownerAccountID + - region + type: object + activityStatus: + description: |- + The progress of the EC2 Fleet. + + For fleets of type instant, the status is fulfilled after all requests are + placed, regardless of whether target capacity is met (this is the only possible + status for instant fleets). + + For fleets of type request or maintain, the status is pending_fulfillment + after all requests are placed, fulfilled when the fleet size meets or exceeds + target capacity, pending_termination while instances are terminating when + fleet size is decreased, and error if there's an error. + type: string + conditions: + description: |- + All CRs managed by ACK have a common `Status.Conditions` member that + contains a collection of `ackv1alpha1.Condition` objects that describe + the various terminal states of the CR and its backend AWS service API + resource + items: + description: |- + Condition is the common struct used by all CRDs managed by ACK service + controllers to indicate terminal states of the CR and its backend AWS + service API resource + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type is the type of the Condition + type: string + required: + - status + - type + type: object + type: array + errors: + description: |- + Information about the instances that could not be launched by the fleet. + Supported only for fleets of type instant. + items: + description: Describes the instances that could not be launched + by the fleet. + properties: + errorCode: + type: string + errorMessage: + type: string + launchTemplateAndOverrides: + description: Describes a launch template and overrides. + properties: + launchTemplateSpecification: + description: |- + The Amazon EC2 launch template that can be used by a Spot Fleet to configure + Amazon EC2 instances. You must specify either the ID or name of the launch + template in the request, but not both. + + For information about launch templates, see Launch an instance from a launch + template (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-templates.html) + in the Amazon EC2 User Guide. + properties: + launchTemplateID: + type: string + launchTemplateName: + type: string + version: + type: string + type: object + overrides: + description: Describes overrides for a launch template. + properties: + availabilityZone: + type: string + blockDeviceMappings: + items: + description: |- + Describes a block device mapping, which defines the EBS volumes and instance + store volumes to attach to an instance at launch. + properties: + deviceName: + type: string + ebs: + description: Describes a block device for an EBS + volume. + properties: + deleteOnTermination: + type: boolean + encrypted: + type: boolean + iops: + format: int64 + type: integer + kmsKeyID: + type: string + snapshotID: + type: string + throughput: + format: int64 + type: integer + volumeSize: + format: int64 + type: integer + volumeType: + type: string + type: object + noDevice: + type: string + virtualName: + type: string + type: object + type: array + imageID: + type: string + instanceRequirements: + description: |- + The attributes for the instance types. When you specify instance attributes, + Amazon EC2 will identify instance types with these attributes. + + You must specify VCpuCount and MemoryMiB. All other attributes are optional. + Any unspecified optional attribute is set to its default. + + When you specify multiple attributes, you get instance types that satisfy + all of the specified attributes. If you specify multiple values for an attribute, + you get instance types that satisfy any of the specified values. + + To limit the list of instance types from which Amazon EC2 can identify matching + instance types, you can use one of the following parameters, but not both + in the same request: + + * AllowedInstanceTypes - The instance types to include in the list. All + other instance types are ignored, even if they match your specified attributes. + + * ExcludedInstanceTypes - The instance types to exclude from the list, + even if they match your specified attributes. + + If you specify InstanceRequirements, you can't specify InstanceType. + + Attribute-based instance type selection is only supported when using Auto + Scaling groups, EC2 Fleet, and Spot Fleet to launch instances. If you plan + to use the launch template in the launch instance wizard (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-instance-wizard.html) + or with the RunInstances API (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html), + you can't specify InstanceRequirements. + + For more information, see Create mixed instances group using attribute-based + instance type selection (https://docs.aws.amazon.com/autoscaling/ec2/userguide/create-mixed-instances-group-attribute-based-instance-type-selection.html) + in the Amazon EC2 Auto Scaling User Guide, and also Specify attributes for + instance type selection for EC2 Fleet or Spot Fleet (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-attribute-based-instance-type-selection.html) + and Spot placement score (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-placement-score.html) + in the Amazon EC2 User Guide. + properties: + acceleratorCount: + description: |- + The minimum and maximum number of accelerators (GPUs, FPGAs, or Amazon Web + Services Inferentia chips) on an instance. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + acceleratorManufacturers: + items: + type: string + type: array + acceleratorNames: + items: + type: string + type: array + acceleratorTotalMemoryMiB: + description: The minimum and maximum amount of total + accelerator memory, in MiB. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + acceleratorTypes: + items: + type: string + type: array + allowedInstanceTypes: + items: + type: string + type: array + bareMetal: + type: string + baselineEBSBandwidthMbps: + description: |- + The minimum and maximum baseline bandwidth to Amazon EBS, in Mbps. For more + information, see Amazon EBS–optimized instances (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-optimized.html) + in the Amazon EC2 User Guide. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + baselinePerformanceFactors: + description: |- + The baseline performance to consider, using an instance family as a baseline + reference. The instance family establishes the lowest acceptable level of + performance. Amazon EC2 uses this baseline to guide instance type selection, + but there is no guarantee that the selected instance types will always exceed + the baseline for every application. + + Currently, this parameter only supports CPU performance as a baseline performance + factor. For example, specifying c6i would use the CPU performance of the + c6i family as the baseline reference. + properties: + cpu: + description: |- + The CPU performance to consider, using an instance family as the baseline + reference. + properties: + references: + items: + description: |- + Specify an instance family to use as the baseline reference for CPU performance. + All instance types that match your specified attributes will be compared + against the CPU performance of the referenced instance family, regardless + of CPU manufacturer or architecture. + + Currently, only one instance family can be specified in the list. + properties: + instanceFamily: + type: string + type: object + type: array + type: object + type: object + burstablePerformance: + type: string + cpuManufacturers: + items: + type: string + type: array + excludedInstanceTypes: + items: + type: string + type: array + instanceGenerations: + items: + type: string + type: array + localStorage: + type: string + localStorageTypes: + items: + type: string + type: array + maxSpotPriceAsPercentageOfOptimalOnDemandPrice: + format: int64 + type: integer + memoryGiBPerVCPU: + description: The minimum and maximum amount of memory + per vCPU, in GiB. + properties: + max: + type: number + min: + type: number + type: object + memoryMiB: + description: The minimum and maximum amount of memory, + in MiB. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + networkBandwidthGbps: + description: |- + The minimum and maximum amount of network bandwidth, in gigabits per second + (Gbps). + + Setting the minimum bandwidth does not guarantee that your instance will + achieve the minimum bandwidth. Amazon EC2 will identify instance types that + support the specified minimum bandwidth, but the actual bandwidth of your + instance might go below the specified minimum at times. For more information, + see Available instance bandwidth (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-network-bandwidth.html#available-instance-bandwidth) + in the Amazon EC2 User Guide. + properties: + max: + type: number + min: + type: number + type: object + networkInterfaceCount: + description: The minimum and maximum number of network + interfaces. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + onDemandMaxPricePercentageOverLowestPrice: + format: int64 + type: integer + requireHibernateSupport: + type: boolean + spotMaxPricePercentageOverLowestPrice: + format: int64 + type: integer + totalLocalStorageGB: + description: The minimum and maximum amount of total + local storage, in GB. + properties: + max: + type: number + min: + type: number + type: object + vCPUCount: + description: The minimum and maximum number of vCPUs. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + type: object + instanceType: + type: string + maxPrice: + type: string + placement: + description: Describes the placement of an instance. + properties: + groupName: + type: string + type: object + priority: + type: number + subnetID: + type: string + weightedCapacity: + type: number + type: object + type: object + lifecycle: + type: string + type: object + type: array + fleetID: + description: The ID of the EC2 Fleet. + type: string + fleetState: + description: The state of the EC2 Fleet. + type: string + fulfilledCapacity: + description: |- + The number of units fulfilled by this request compared to the set target + capacity. + type: number + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index e820be33..7f4a615b 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -5,6 +5,7 @@ resources: - bases/ec2.services.k8s.aws_capacityreservations.yaml - bases/ec2.services.k8s.aws_dhcpoptions.yaml - bases/ec2.services.k8s.aws_elasticipaddresses.yaml + - bases/ec2.services.k8s.aws_fleets.yaml - bases/ec2.services.k8s.aws_flowlogs.yaml - bases/ec2.services.k8s.aws_instances.yaml - bases/ec2.services.k8s.aws_internetgateways.yaml diff --git a/config/rbac/cluster-role-controller.yaml b/config/rbac/cluster-role-controller.yaml index 229b3b66..c40e14d3 100644 --- a/config/rbac/cluster-role-controller.yaml +++ b/config/rbac/cluster-role-controller.yaml @@ -28,6 +28,7 @@ rules: - capacityreservations - dhcpoptions - elasticipaddresses + - fleets - flowlogs - instances - internetgateways @@ -58,6 +59,7 @@ rules: - capacityreservations/status - dhcpoptions/status - elasticipaddresses/status + - fleets/status - flowlogs/status - instances/status - internetgateways/status diff --git a/config/rbac/role-reader.yaml b/config/rbac/role-reader.yaml index 6b1b9dde..c0cb1fd8 100644 --- a/config/rbac/role-reader.yaml +++ b/config/rbac/role-reader.yaml @@ -12,6 +12,7 @@ rules: - capacityreservations - dhcpoptions - elasticipaddresses + - fleets - flowlogs - instances - internetgateways diff --git a/config/rbac/role-writer.yaml b/config/rbac/role-writer.yaml index 91b23947..60c28861 100644 --- a/config/rbac/role-writer.yaml +++ b/config/rbac/role-writer.yaml @@ -12,6 +12,7 @@ rules: - capacityreservations - dhcpoptions - elasticipaddresses + - fleets - flowlogs - instances - internetgateways @@ -42,6 +43,7 @@ rules: - capacityreservations - dhcpoptions - elasticipaddresses + - fleets - flowlogs - instances - internetgateways diff --git a/generator.yaml b/generator.yaml index f2c76e1c..ad83102d 100644 --- a/generator.yaml +++ b/generator.yaml @@ -155,6 +155,12 @@ ignore: - ManagedPrefixList.IpamPrefixListResolverSyncEnabled - ManagedPrefixList.IpamPrefixListResolverTargetId - CreateLaunchTemplateVersionOutput.LaunchTemplateVersion.DefaultVersion + - CreateFleetInput.ClientToken + - CreateFleetInput.TagSpecifications + - CreateFleetInput.DryRun + - CreateFleetOutput.Instances + - FleetLaunchTemplateOverrides.AvailabilityZoneId + - FleetLaunchTemplateOverridesRequest.AvailabilityZoneId resource_names: - CapacityReservationBySplitting - IpamExternalResourceVerificationToken @@ -174,7 +180,7 @@ ignore: - DelegateMacVolumeOwnershipTask #- DhcpOptions - EgressOnlyInternetGateway - - Fleet + # - Fleet - FpgaImage - Image - ImageUsageReport @@ -320,6 +326,10 @@ operations: operation_type: - Delete resource_name: FlowLog + DeleteFleets: + operation_type: + - Delete + resource_name: Fleet RunInstances: #ouput shape: Reservation output_wrapper_field_path: Instances @@ -1264,3 +1274,99 @@ resources: template_path: hooks/vpc_peering_connection/sdk_read_many_post_set_output.go.tpl sdk_file_end: template_path: hooks/vpc_peering_connection/sdk_file_end.go.tpl + Fleet: + fields: + FleetID: + is_primary_key: true + is_read_only: true + print: + name: ID + Tags: + from: + operation: CreateTags + path: Tags + FleetState: + is_read_only: true + from: + operation: DescribeFleets + path: Fleets.FleetState + ActivityStatus: + is_read_only: true + from: + operation: DescribeFleets + path: Fleets.ActivityStatus + FulfilledCapacity: + is_read_only: true + from: + operation: DescribeFleets + path: Fleets.FulfilledCapacity + Type: + late_initialize: + skip_incomplete_check: {} + is_immutable: true + go_tag: json:"type,omitempty" + TerminateInstancesOnDeletion: + type: bool + ReplaceUnhealthyInstances: + late_initialize: + skip_incomplete_check: {} + is_immutable: true + TerminateInstancesWithExpiration: + late_initialize: + skip_incomplete_check: {} + is_immutable: true + ExcessCapacityTerminationPolicy: + late_initialize: + skip_incomplete_check: {} + SpotOptions: + late_initialize: + skip_incomplete_check: {} + is_immutable: true + OnDemandOptions: + late_initialize: + skip_incomplete_check: {} + is_immutable: true + ValidFrom: + late_initialize: + skip_incomplete_check: {} + is_immutable: true + ValidUntil: + late_initialize: + skip_incomplete_check: {} + is_immutable: true + TargetCapacitySpecification.OnDemandTargetCapacity: + late_initialize: + skip_incomplete_check: {} + TargetCapacitySpecification.SpotTargetCapacity: + late_initialize: + skip_incomplete_check: {} + TargetCapacitySpecification.DefaultTargetCapacityType: + is_immutable: true + synced: + when: + - path: Status.ActivityStatus + in: + - fulfilled + - path: Status.FleetState + in: + - active + exceptions: + terminal_codes: + - InvalidParameterValue + hooks: + delta_pre_compare: + code: customPreCompare(delta, a, b) + sdk_create_post_build_request: + template_path: hooks/fleet/sdk_create_post_build_request.go.tpl + sdk_read_many_post_set_output: + template_path: hooks/fleet/sdk_read_many_post_set_output.go.tpl + sdk_delete_pre_build_request: + template_path: hooks/fleet/sdk_delete_pre_build_request.go.tpl + sdk_delete_post_build_request: + template_path: hooks/fleet/sdk_delete_post_build_request.go.tpl + sdk_update_pre_build_request: + template_path: hooks/fleet/sdk_update_pre_build_request.go.tpl + sdk_update_pre_set_output: + template_path: hooks/fleet/sdk_update_pre_set_output.go.tpl + sdk_file_end: + template_path: hooks/fleet/sdk_file_end.go.tpl diff --git a/helm/crds/ec2.services.k8s.aws_fleets.yaml b/helm/crds/ec2.services.k8s.aws_fleets.yaml new file mode 100644 index 00000000..f71796df --- /dev/null +++ b/helm/crds/ec2.services.k8s.aws_fleets.yaml @@ -0,0 +1,994 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + name: fleets.ec2.services.k8s.aws +spec: + group: ec2.services.k8s.aws + names: + kind: Fleet + listKind: FleetList + plural: fleets + singular: fleet + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.fleetID + name: ID + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Fleet is the Schema for the Fleets API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: FleetSpec defines the desired state of Fleet. + properties: + context: + description: Reserved. + type: string + excessCapacityTerminationPolicy: + description: |- + Indicates whether running instances should be terminated if the total target + capacity of the EC2 Fleet is decreased below the current size of the EC2 + Fleet. + + Supported only for fleets of type maintain. + type: string + launchTemplateConfigs: + description: The configuration for the EC2 Fleet. + items: + description: Describes a launch template and overrides. + properties: + launchTemplateSpecification: + description: |- + The Amazon EC2 launch template that can be used by an EC2 Fleet to configure + Amazon EC2 instances. You must specify either the ID or name of the launch + template in the request, but not both. + + For information about launch templates, see Launch an instance from a launch + template (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-templates.html) + in the Amazon EC2 User Guide. + properties: + launchTemplateID: + type: string + launchTemplateName: + type: string + version: + type: string + type: object + overrides: + items: + description: Describes overrides for a launch template. + properties: + availabilityZone: + type: string + blockDeviceMappings: + items: + description: |- + Describes a block device mapping, which defines the EBS volumes and instance + store volumes to attach to an instance at launch. + + To override a block device mapping specified in the launch template: + + - Specify the exact same DeviceName here as specified in the launch template. + + - Only specify the parameters you want to change. + + - Any parameters you don't specify here will keep their original launch + template values. + + To add a new block device mapping: + + - Specify a DeviceName that doesn't exist in the launch template. + + - Specify all desired parameters here. + properties: + deviceName: + type: string + ebs: + description: Describes a block device for an EBS + volume. + properties: + deleteOnTermination: + type: boolean + encrypted: + type: boolean + iops: + format: int64 + type: integer + kmsKeyID: + type: string + snapshotID: + type: string + throughput: + format: int64 + type: integer + volumeSize: + format: int64 + type: integer + volumeType: + type: string + type: object + noDevice: + type: string + virtualName: + type: string + type: object + type: array + imageID: + type: string + instanceRequirements: + description: |- + The attributes for the instance types. When you specify instance attributes, + Amazon EC2 will identify instance types with these attributes. + + You must specify VCpuCount and MemoryMiB. All other attributes are optional. + Any unspecified optional attribute is set to its default. + + When you specify multiple attributes, you get instance types that satisfy + all of the specified attributes. If you specify multiple values for an attribute, + you get instance types that satisfy any of the specified values. + + To limit the list of instance types from which Amazon EC2 can identify matching + instance types, you can use one of the following parameters, but not both + in the same request: + + * AllowedInstanceTypes - The instance types to include in the list. All + other instance types are ignored, even if they match your specified attributes. + + * ExcludedInstanceTypes - The instance types to exclude from the list, + even if they match your specified attributes. + + If you specify InstanceRequirements, you can't specify InstanceType. + + Attribute-based instance type selection is only supported when using Auto + Scaling groups, EC2 Fleet, and Spot Fleet to launch instances. If you plan + to use the launch template in the launch instance wizard (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-instance-wizard.html), + or with the RunInstances (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html) + API or AWS::EC2::Instance (https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html) + Amazon Web Services CloudFormation resource, you can't specify InstanceRequirements. + + For more information, see Specify attributes for instance type selection + for EC2 Fleet or Spot Fleet (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-attribute-based-instance-type-selection.html) + and Spot placement score (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-placement-score.html) + in the Amazon EC2 User Guide. + properties: + acceleratorCount: + description: |- + The minimum and maximum number of accelerators (GPUs, FPGAs, or Amazon Web + Services Inferentia chips) on an instance. To exclude accelerator-enabled + instance types, set Max to 0. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + acceleratorManufacturers: + items: + type: string + type: array + acceleratorNames: + items: + type: string + type: array + acceleratorTotalMemoryMiB: + description: The minimum and maximum amount of total + accelerator memory, in MiB. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + acceleratorTypes: + items: + type: string + type: array + allowedInstanceTypes: + items: + type: string + type: array + bareMetal: + type: string + baselineEBSBandwidthMbps: + description: |- + The minimum and maximum baseline bandwidth to Amazon EBS, in Mbps. For more + information, see Amazon EBS–optimized instances (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-optimized.html) + in the Amazon EC2 User Guide. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + baselinePerformanceFactors: + description: |- + The baseline performance to consider, using an instance family as a baseline + reference. The instance family establishes the lowest acceptable level of + performance. Amazon EC2 uses this baseline to guide instance type selection, + but there is no guarantee that the selected instance types will always exceed + the baseline for every application. + + Currently, this parameter only supports CPU performance as a baseline performance + factor. For example, specifying c6i would use the CPU performance of the + c6i family as the baseline reference. + properties: + cpu: + description: |- + The CPU performance to consider, using an instance family as the baseline + reference. + properties: + references: + items: + description: |- + Specify an instance family to use as the baseline reference for CPU performance. + All instance types that match your specified attributes will be compared + against the CPU performance of the referenced instance family, regardless + of CPU manufacturer or architecture. + + Currently, only one instance family can be specified in the list. + properties: + instanceFamily: + type: string + type: object + type: array + type: object + type: object + burstablePerformance: + type: string + cpuManufacturers: + items: + type: string + type: array + excludedInstanceTypes: + items: + type: string + type: array + instanceGenerations: + items: + type: string + type: array + localStorage: + type: string + localStorageTypes: + items: + type: string + type: array + maxSpotPriceAsPercentageOfOptimalOnDemandPrice: + format: int64 + type: integer + memoryGiBPerVCPU: + description: The minimum and maximum amount of memory + per vCPU, in GiB. + properties: + max: + type: number + min: + type: number + type: object + memoryMiB: + description: The minimum and maximum amount of memory, + in MiB. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + networkBandwidthGbps: + description: |- + The minimum and maximum amount of network bandwidth, in gigabits per second + (Gbps). + + Setting the minimum bandwidth does not guarantee that your instance will + achieve the minimum bandwidth. Amazon EC2 will identify instance types that + support the specified minimum bandwidth, but the actual bandwidth of your + instance might go below the specified minimum at times. For more information, + see Available instance bandwidth (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-network-bandwidth.html#available-instance-bandwidth) + in the Amazon EC2 User Guide. + properties: + max: + type: number + min: + type: number + type: object + networkInterfaceCount: + description: The minimum and maximum number of network + interfaces. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + onDemandMaxPricePercentageOverLowestPrice: + format: int64 + type: integer + requireHibernateSupport: + type: boolean + spotMaxPricePercentageOverLowestPrice: + format: int64 + type: integer + totalLocalStorageGB: + description: The minimum and maximum amount of total + local storage, in GB. + properties: + max: + type: number + min: + type: number + type: object + vCPUCount: + description: The minimum and maximum number of vCPUs. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + type: object + instanceType: + type: string + maxPrice: + type: string + placement: + description: Describes the placement of an instance. + properties: + affinity: + type: string + availabilityZone: + type: string + groupName: + type: string + hostID: + type: string + hostResourceGroupARN: + type: string + partitionNumber: + format: int64 + type: integer + spreadDomain: + type: string + tenancy: + type: string + type: object + priority: + type: number + subnetID: + type: string + weightedCapacity: + type: number + type: object + type: array + type: object + type: array + onDemandOptions: + description: Describes the configuration of On-Demand Instances in + an EC2 Fleet. + properties: + allocationStrategy: + type: string + capacityReservationOptions: + description: |- + Describes the strategy for using unused Capacity Reservations for fulfilling + On-Demand capacity. + + This strategy can only be used if the EC2 Fleet is of type instant. + + For more information about Capacity Reservations, see On-Demand Capacity + Reservations (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-capacity-reservations.html) + in the Amazon EC2 User Guide. For examples of using Capacity Reservations + in an EC2 Fleet, see EC2 Fleet example configurations (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-examples.html) + in the Amazon EC2 User Guide. + properties: + usageStrategy: + type: string + type: object + maxTotalPrice: + type: string + minTargetCapacity: + format: int64 + type: integer + singleAvailabilityZone: + type: boolean + singleInstanceType: + type: boolean + type: object + x-kubernetes-validations: + - message: Value is immutable once set + rule: self == oldSelf + replaceUnhealthyInstances: + description: |- + Indicates whether EC2 Fleet should replace unhealthy Spot Instances. Supported + only for fleets of type maintain. For more information, see EC2 Fleet health + checks (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/manage-ec2-fleet.html#ec2-fleet-health-checks) + in the Amazon EC2 User Guide. + type: boolean + x-kubernetes-validations: + - message: Value is immutable once set + rule: self == oldSelf + spotOptions: + description: Describes the configuration of Spot Instances in an EC2 + Fleet. + properties: + allocationStrategy: + type: string + instanceInterruptionBehavior: + type: string + instancePoolsToUseCount: + format: int64 + type: integer + maintenanceStrategies: + description: |- + The strategies for managing your Spot Instances that are at an elevated risk + of being interrupted. + properties: + capacityRebalance: + description: |- + The Spot Instance replacement strategy to use when Amazon EC2 emits a rebalance + notification signal that your Spot Instance is at an elevated risk of being + interrupted. For more information, see Capacity rebalancing (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-capacity-rebalance.html) + in the Amazon EC2 User Guide. + properties: + replacementStrategy: + type: string + terminationDelay: + format: int64 + type: integer + type: object + type: object + maxTotalPrice: + type: string + minTargetCapacity: + format: int64 + type: integer + singleAvailabilityZone: + type: boolean + singleInstanceType: + type: boolean + type: object + x-kubernetes-validations: + - message: Value is immutable once set + rule: self == oldSelf + tags: + description: |- + The tags. The value parameter is required, but if you don't want the tag + to have a value, specify the parameter with no value, and we set the value + to an empty string. + items: + description: Describes a tag. + properties: + key: + type: string + value: + type: string + type: object + type: array + targetCapacitySpecification: + description: The number of units to request. + properties: + defaultTargetCapacityType: + type: string + x-kubernetes-validations: + - message: Value is immutable once set + rule: self == oldSelf + onDemandTargetCapacity: + format: int64 + type: integer + spotTargetCapacity: + format: int64 + type: integer + targetCapacityUnitType: + type: string + totalTargetCapacity: + format: int64 + type: integer + type: object + terminateInstancesOnDeletion: + type: boolean + terminateInstancesWithExpiration: + description: |- + Indicates whether running instances should be terminated when the EC2 Fleet + expires. + type: boolean + x-kubernetes-validations: + - message: Value is immutable once set + rule: self == oldSelf + type: + description: |- + The fleet type. The default value is maintain. + + - maintain - The EC2 Fleet places an asynchronous request for your desired + capacity, and continues to maintain your desired Spot capacity by replenishing + interrupted Spot Instances. + + - request - The EC2 Fleet places an asynchronous one-time request for + your desired capacity, but does submit Spot requests in alternative capacity + pools if Spot capacity is unavailable, and does not maintain Spot capacity + if Spot Instances are interrupted. + + - instant - The EC2 Fleet places a synchronous one-time request for your + desired capacity, and returns errors for any instances that could not + be launched. + + For more information, see EC2 Fleet request types (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-request-type.html) + in the Amazon EC2 User Guide. + type: string + x-kubernetes-validations: + - message: Value is immutable once set + rule: self == oldSelf + validFrom: + description: |- + The start date and time of the request, in UTC format (for example, YYYY-MM-DDTHH:MM:SSZ). + The default is to start fulfilling the request immediately. + format: date-time + type: string + x-kubernetes-validations: + - message: Value is immutable once set + rule: self == oldSelf + validUntil: + description: |- + The end date and time of the request, in UTC format (for example, YYYY-MM-DDTHH:MM:SSZ). + At this point, no new EC2 Fleet requests are placed or able to fulfill the + request. If no value is specified, the request remains until you cancel it. + format: date-time + type: string + x-kubernetes-validations: + - message: Value is immutable once set + rule: self == oldSelf + required: + - launchTemplateConfigs + - targetCapacitySpecification + type: object + status: + description: FleetStatus defines the observed state of Fleet + properties: + ackResourceMetadata: + description: |- + All CRs managed by ACK have a common `Status.ACKResourceMetadata` member + that is used to contain resource sync state, account ownership, + constructed ARN for the resource + properties: + arn: + description: |- + ARN is the Amazon Resource Name for the resource. This is a + globally-unique identifier and is set only by the ACK service controller + once the controller has orchestrated the creation of the resource OR + when it has verified that an "adopted" resource (a resource where the + ARN annotation was set by the Kubernetes user on the CR) exists and + matches the supplied CR's Spec field values. + https://github.com/aws/aws-controllers-k8s/issues/270 + type: string + ownerAccountID: + description: |- + OwnerAccountID is the AWS Account ID of the account that owns the + backend AWS service API resource. + type: string + region: + description: Region is the AWS region in which the resource exists + or will exist. + type: string + required: + - ownerAccountID + - region + type: object + activityStatus: + description: |- + The progress of the EC2 Fleet. + + For fleets of type instant, the status is fulfilled after all requests are + placed, regardless of whether target capacity is met (this is the only possible + status for instant fleets). + + For fleets of type request or maintain, the status is pending_fulfillment + after all requests are placed, fulfilled when the fleet size meets or exceeds + target capacity, pending_termination while instances are terminating when + fleet size is decreased, and error if there's an error. + type: string + conditions: + description: |- + All CRs managed by ACK have a common `Status.Conditions` member that + contains a collection of `ackv1alpha1.Condition` objects that describe + the various terminal states of the CR and its backend AWS service API + resource + items: + description: |- + Condition is the common struct used by all CRDs managed by ACK service + controllers to indicate terminal states of the CR and its backend AWS + service API resource + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type is the type of the Condition + type: string + required: + - status + - type + type: object + type: array + errors: + description: |- + Information about the instances that could not be launched by the fleet. + Supported only for fleets of type instant. + items: + description: Describes the instances that could not be launched + by the fleet. + properties: + errorCode: + type: string + errorMessage: + type: string + launchTemplateAndOverrides: + description: Describes a launch template and overrides. + properties: + launchTemplateSpecification: + description: |- + The Amazon EC2 launch template that can be used by a Spot Fleet to configure + Amazon EC2 instances. You must specify either the ID or name of the launch + template in the request, but not both. + + For information about launch templates, see Launch an instance from a launch + template (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-templates.html) + in the Amazon EC2 User Guide. + properties: + launchTemplateID: + type: string + launchTemplateName: + type: string + version: + type: string + type: object + overrides: + description: Describes overrides for a launch template. + properties: + availabilityZone: + type: string + blockDeviceMappings: + items: + description: |- + Describes a block device mapping, which defines the EBS volumes and instance + store volumes to attach to an instance at launch. + properties: + deviceName: + type: string + ebs: + description: Describes a block device for an EBS + volume. + properties: + deleteOnTermination: + type: boolean + encrypted: + type: boolean + iops: + format: int64 + type: integer + kmsKeyID: + type: string + snapshotID: + type: string + throughput: + format: int64 + type: integer + volumeSize: + format: int64 + type: integer + volumeType: + type: string + type: object + noDevice: + type: string + virtualName: + type: string + type: object + type: array + imageID: + type: string + instanceRequirements: + description: |- + The attributes for the instance types. When you specify instance attributes, + Amazon EC2 will identify instance types with these attributes. + + You must specify VCpuCount and MemoryMiB. All other attributes are optional. + Any unspecified optional attribute is set to its default. + + When you specify multiple attributes, you get instance types that satisfy + all of the specified attributes. If you specify multiple values for an attribute, + you get instance types that satisfy any of the specified values. + + To limit the list of instance types from which Amazon EC2 can identify matching + instance types, you can use one of the following parameters, but not both + in the same request: + + * AllowedInstanceTypes - The instance types to include in the list. All + other instance types are ignored, even if they match your specified attributes. + + * ExcludedInstanceTypes - The instance types to exclude from the list, + even if they match your specified attributes. + + If you specify InstanceRequirements, you can't specify InstanceType. + + Attribute-based instance type selection is only supported when using Auto + Scaling groups, EC2 Fleet, and Spot Fleet to launch instances. If you plan + to use the launch template in the launch instance wizard (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-instance-wizard.html) + or with the RunInstances API (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html), + you can't specify InstanceRequirements. + + For more information, see Create mixed instances group using attribute-based + instance type selection (https://docs.aws.amazon.com/autoscaling/ec2/userguide/create-mixed-instances-group-attribute-based-instance-type-selection.html) + in the Amazon EC2 Auto Scaling User Guide, and also Specify attributes for + instance type selection for EC2 Fleet or Spot Fleet (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-attribute-based-instance-type-selection.html) + and Spot placement score (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-placement-score.html) + in the Amazon EC2 User Guide. + properties: + acceleratorCount: + description: |- + The minimum and maximum number of accelerators (GPUs, FPGAs, or Amazon Web + Services Inferentia chips) on an instance. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + acceleratorManufacturers: + items: + type: string + type: array + acceleratorNames: + items: + type: string + type: array + acceleratorTotalMemoryMiB: + description: The minimum and maximum amount of total + accelerator memory, in MiB. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + acceleratorTypes: + items: + type: string + type: array + allowedInstanceTypes: + items: + type: string + type: array + bareMetal: + type: string + baselineEBSBandwidthMbps: + description: |- + The minimum and maximum baseline bandwidth to Amazon EBS, in Mbps. For more + information, see Amazon EBS–optimized instances (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-optimized.html) + in the Amazon EC2 User Guide. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + baselinePerformanceFactors: + description: |- + The baseline performance to consider, using an instance family as a baseline + reference. The instance family establishes the lowest acceptable level of + performance. Amazon EC2 uses this baseline to guide instance type selection, + but there is no guarantee that the selected instance types will always exceed + the baseline for every application. + + Currently, this parameter only supports CPU performance as a baseline performance + factor. For example, specifying c6i would use the CPU performance of the + c6i family as the baseline reference. + properties: + cpu: + description: |- + The CPU performance to consider, using an instance family as the baseline + reference. + properties: + references: + items: + description: |- + Specify an instance family to use as the baseline reference for CPU performance. + All instance types that match your specified attributes will be compared + against the CPU performance of the referenced instance family, regardless + of CPU manufacturer or architecture. + + Currently, only one instance family can be specified in the list. + properties: + instanceFamily: + type: string + type: object + type: array + type: object + type: object + burstablePerformance: + type: string + cpuManufacturers: + items: + type: string + type: array + excludedInstanceTypes: + items: + type: string + type: array + instanceGenerations: + items: + type: string + type: array + localStorage: + type: string + localStorageTypes: + items: + type: string + type: array + maxSpotPriceAsPercentageOfOptimalOnDemandPrice: + format: int64 + type: integer + memoryGiBPerVCPU: + description: The minimum and maximum amount of memory + per vCPU, in GiB. + properties: + max: + type: number + min: + type: number + type: object + memoryMiB: + description: The minimum and maximum amount of memory, + in MiB. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + networkBandwidthGbps: + description: |- + The minimum and maximum amount of network bandwidth, in gigabits per second + (Gbps). + + Setting the minimum bandwidth does not guarantee that your instance will + achieve the minimum bandwidth. Amazon EC2 will identify instance types that + support the specified minimum bandwidth, but the actual bandwidth of your + instance might go below the specified minimum at times. For more information, + see Available instance bandwidth (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-network-bandwidth.html#available-instance-bandwidth) + in the Amazon EC2 User Guide. + properties: + max: + type: number + min: + type: number + type: object + networkInterfaceCount: + description: The minimum and maximum number of network + interfaces. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + onDemandMaxPricePercentageOverLowestPrice: + format: int64 + type: integer + requireHibernateSupport: + type: boolean + spotMaxPricePercentageOverLowestPrice: + format: int64 + type: integer + totalLocalStorageGB: + description: The minimum and maximum amount of total + local storage, in GB. + properties: + max: + type: number + min: + type: number + type: object + vCPUCount: + description: The minimum and maximum number of vCPUs. + properties: + max: + format: int64 + type: integer + min: + format: int64 + type: integer + type: object + type: object + instanceType: + type: string + maxPrice: + type: string + placement: + description: Describes the placement of an instance. + properties: + groupName: + type: string + type: object + priority: + type: number + subnetID: + type: string + weightedCapacity: + type: number + type: object + type: object + lifecycle: + type: string + type: object + type: array + fleetID: + description: The ID of the EC2 Fleet. + type: string + fleetState: + description: The state of the EC2 Fleet. + type: string + fulfilledCapacity: + description: |- + The number of units fulfilled by this request compared to the set target + capacity. + type: number + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl index 4f6a4004..c1a453b0 100644 --- a/helm/templates/_helpers.tpl +++ b/helm/templates/_helpers.tpl @@ -75,6 +75,7 @@ rules: - capacityreservations - dhcpoptions - elasticipaddresses + - fleets - flowlogs - instances - internetgateways @@ -105,6 +106,7 @@ rules: - capacityreservations/status - dhcpoptions/status - elasticipaddresses/status + - fleets/status - flowlogs/status - instances/status - internetgateways/status diff --git a/helm/templates/role-reader.yaml b/helm/templates/role-reader.yaml index cfe2b49c..8eb8150a 100644 --- a/helm/templates/role-reader.yaml +++ b/helm/templates/role-reader.yaml @@ -19,6 +19,7 @@ rules: - capacityreservations - dhcpoptions - elasticipaddresses + - fleets - flowlogs - instances - internetgateways diff --git a/helm/templates/role-writer.yaml b/helm/templates/role-writer.yaml index ba9465f0..fcf9ebe5 100644 --- a/helm/templates/role-writer.yaml +++ b/helm/templates/role-writer.yaml @@ -19,6 +19,7 @@ rules: - capacityreservations - dhcpoptions - elasticipaddresses + - fleets - flowlogs - instances - internetgateways @@ -49,6 +50,7 @@ rules: - capacityreservations - dhcpoptions - elasticipaddresses + - fleets - flowlogs - instances - internetgateways diff --git a/helm/values.yaml b/helm/values.yaml index bb7fa044..bb93811c 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -153,6 +153,7 @@ reconcile: - CapacityReservation - DHCPOptions - ElasticIPAddress + - Fleet - FlowLog - Instance - InternetGateway diff --git a/pkg/resource/fleet/delta.go b/pkg/resource/fleet/delta.go new file mode 100644 index 00000000..adc37d23 --- /dev/null +++ b/pkg/resource/fleet/delta.go @@ -0,0 +1,280 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package fleet + +import ( + "bytes" + + ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" + acktags "github.com/aws-controllers-k8s/runtime/pkg/tags" + "k8s.io/apimachinery/pkg/api/equality" +) + +// Hack to avoid import errors during build... +var ( + _ = &bytes.Buffer{} + _ = &acktags.Tags{} +) + +// newResourceDelta returns a new `ackcompare.Delta` used to compare two +// resources +func newResourceDelta( + a *resource, + b *resource, +) *ackcompare.Delta { + delta := ackcompare.NewDelta() + if (a == nil && b != nil) || + (a != nil && b == nil) { + delta.Add("", a, b) + return delta + } + customPreCompare(delta, a, b) + + if ackcompare.HasNilDifference(a.ko.Spec.Context, b.ko.Spec.Context) { + delta.Add("Spec.Context", a.ko.Spec.Context, b.ko.Spec.Context) + } else if a.ko.Spec.Context != nil && b.ko.Spec.Context != nil { + if *a.ko.Spec.Context != *b.ko.Spec.Context { + delta.Add("Spec.Context", a.ko.Spec.Context, b.ko.Spec.Context) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.ExcessCapacityTerminationPolicy, b.ko.Spec.ExcessCapacityTerminationPolicy) { + delta.Add("Spec.ExcessCapacityTerminationPolicy", a.ko.Spec.ExcessCapacityTerminationPolicy, b.ko.Spec.ExcessCapacityTerminationPolicy) + } else if a.ko.Spec.ExcessCapacityTerminationPolicy != nil && b.ko.Spec.ExcessCapacityTerminationPolicy != nil { + if *a.ko.Spec.ExcessCapacityTerminationPolicy != *b.ko.Spec.ExcessCapacityTerminationPolicy { + delta.Add("Spec.ExcessCapacityTerminationPolicy", a.ko.Spec.ExcessCapacityTerminationPolicy, b.ko.Spec.ExcessCapacityTerminationPolicy) + } + } + if len(a.ko.Spec.LaunchTemplateConfigs) != len(b.ko.Spec.LaunchTemplateConfigs) { + delta.Add("Spec.LaunchTemplateConfigs", a.ko.Spec.LaunchTemplateConfigs, b.ko.Spec.LaunchTemplateConfigs) + } else if len(a.ko.Spec.LaunchTemplateConfigs) > 0 { + if !equality.Semantic.Equalities.DeepEqual(a.ko.Spec.LaunchTemplateConfigs, b.ko.Spec.LaunchTemplateConfigs) { + delta.Add("Spec.LaunchTemplateConfigs", a.ko.Spec.LaunchTemplateConfigs, b.ko.Spec.LaunchTemplateConfigs) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.OnDemandOptions, b.ko.Spec.OnDemandOptions) { + delta.Add("Spec.OnDemandOptions", a.ko.Spec.OnDemandOptions, b.ko.Spec.OnDemandOptions) + } else if a.ko.Spec.OnDemandOptions != nil && b.ko.Spec.OnDemandOptions != nil { + if ackcompare.HasNilDifference(a.ko.Spec.OnDemandOptions.AllocationStrategy, b.ko.Spec.OnDemandOptions.AllocationStrategy) { + delta.Add("Spec.OnDemandOptions.AllocationStrategy", a.ko.Spec.OnDemandOptions.AllocationStrategy, b.ko.Spec.OnDemandOptions.AllocationStrategy) + } else if a.ko.Spec.OnDemandOptions.AllocationStrategy != nil && b.ko.Spec.OnDemandOptions.AllocationStrategy != nil { + if *a.ko.Spec.OnDemandOptions.AllocationStrategy != *b.ko.Spec.OnDemandOptions.AllocationStrategy { + delta.Add("Spec.OnDemandOptions.AllocationStrategy", a.ko.Spec.OnDemandOptions.AllocationStrategy, b.ko.Spec.OnDemandOptions.AllocationStrategy) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.OnDemandOptions.CapacityReservationOptions, b.ko.Spec.OnDemandOptions.CapacityReservationOptions) { + delta.Add("Spec.OnDemandOptions.CapacityReservationOptions", a.ko.Spec.OnDemandOptions.CapacityReservationOptions, b.ko.Spec.OnDemandOptions.CapacityReservationOptions) + } else if a.ko.Spec.OnDemandOptions.CapacityReservationOptions != nil && b.ko.Spec.OnDemandOptions.CapacityReservationOptions != nil { + if ackcompare.HasNilDifference(a.ko.Spec.OnDemandOptions.CapacityReservationOptions.UsageStrategy, b.ko.Spec.OnDemandOptions.CapacityReservationOptions.UsageStrategy) { + delta.Add("Spec.OnDemandOptions.CapacityReservationOptions.UsageStrategy", a.ko.Spec.OnDemandOptions.CapacityReservationOptions.UsageStrategy, b.ko.Spec.OnDemandOptions.CapacityReservationOptions.UsageStrategy) + } else if a.ko.Spec.OnDemandOptions.CapacityReservationOptions.UsageStrategy != nil && b.ko.Spec.OnDemandOptions.CapacityReservationOptions.UsageStrategy != nil { + if *a.ko.Spec.OnDemandOptions.CapacityReservationOptions.UsageStrategy != *b.ko.Spec.OnDemandOptions.CapacityReservationOptions.UsageStrategy { + delta.Add("Spec.OnDemandOptions.CapacityReservationOptions.UsageStrategy", a.ko.Spec.OnDemandOptions.CapacityReservationOptions.UsageStrategy, b.ko.Spec.OnDemandOptions.CapacityReservationOptions.UsageStrategy) + } + } + } + if ackcompare.HasNilDifference(a.ko.Spec.OnDemandOptions.MaxTotalPrice, b.ko.Spec.OnDemandOptions.MaxTotalPrice) { + delta.Add("Spec.OnDemandOptions.MaxTotalPrice", a.ko.Spec.OnDemandOptions.MaxTotalPrice, b.ko.Spec.OnDemandOptions.MaxTotalPrice) + } else if a.ko.Spec.OnDemandOptions.MaxTotalPrice != nil && b.ko.Spec.OnDemandOptions.MaxTotalPrice != nil { + if *a.ko.Spec.OnDemandOptions.MaxTotalPrice != *b.ko.Spec.OnDemandOptions.MaxTotalPrice { + delta.Add("Spec.OnDemandOptions.MaxTotalPrice", a.ko.Spec.OnDemandOptions.MaxTotalPrice, b.ko.Spec.OnDemandOptions.MaxTotalPrice) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.OnDemandOptions.MinTargetCapacity, b.ko.Spec.OnDemandOptions.MinTargetCapacity) { + delta.Add("Spec.OnDemandOptions.MinTargetCapacity", a.ko.Spec.OnDemandOptions.MinTargetCapacity, b.ko.Spec.OnDemandOptions.MinTargetCapacity) + } else if a.ko.Spec.OnDemandOptions.MinTargetCapacity != nil && b.ko.Spec.OnDemandOptions.MinTargetCapacity != nil { + if *a.ko.Spec.OnDemandOptions.MinTargetCapacity != *b.ko.Spec.OnDemandOptions.MinTargetCapacity { + delta.Add("Spec.OnDemandOptions.MinTargetCapacity", a.ko.Spec.OnDemandOptions.MinTargetCapacity, b.ko.Spec.OnDemandOptions.MinTargetCapacity) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.OnDemandOptions.SingleAvailabilityZone, b.ko.Spec.OnDemandOptions.SingleAvailabilityZone) { + delta.Add("Spec.OnDemandOptions.SingleAvailabilityZone", a.ko.Spec.OnDemandOptions.SingleAvailabilityZone, b.ko.Spec.OnDemandOptions.SingleAvailabilityZone) + } else if a.ko.Spec.OnDemandOptions.SingleAvailabilityZone != nil && b.ko.Spec.OnDemandOptions.SingleAvailabilityZone != nil { + if *a.ko.Spec.OnDemandOptions.SingleAvailabilityZone != *b.ko.Spec.OnDemandOptions.SingleAvailabilityZone { + delta.Add("Spec.OnDemandOptions.SingleAvailabilityZone", a.ko.Spec.OnDemandOptions.SingleAvailabilityZone, b.ko.Spec.OnDemandOptions.SingleAvailabilityZone) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.OnDemandOptions.SingleInstanceType, b.ko.Spec.OnDemandOptions.SingleInstanceType) { + delta.Add("Spec.OnDemandOptions.SingleInstanceType", a.ko.Spec.OnDemandOptions.SingleInstanceType, b.ko.Spec.OnDemandOptions.SingleInstanceType) + } else if a.ko.Spec.OnDemandOptions.SingleInstanceType != nil && b.ko.Spec.OnDemandOptions.SingleInstanceType != nil { + if *a.ko.Spec.OnDemandOptions.SingleInstanceType != *b.ko.Spec.OnDemandOptions.SingleInstanceType { + delta.Add("Spec.OnDemandOptions.SingleInstanceType", a.ko.Spec.OnDemandOptions.SingleInstanceType, b.ko.Spec.OnDemandOptions.SingleInstanceType) + } + } + } + if ackcompare.HasNilDifference(a.ko.Spec.ReplaceUnhealthyInstances, b.ko.Spec.ReplaceUnhealthyInstances) { + delta.Add("Spec.ReplaceUnhealthyInstances", a.ko.Spec.ReplaceUnhealthyInstances, b.ko.Spec.ReplaceUnhealthyInstances) + } else if a.ko.Spec.ReplaceUnhealthyInstances != nil && b.ko.Spec.ReplaceUnhealthyInstances != nil { + if *a.ko.Spec.ReplaceUnhealthyInstances != *b.ko.Spec.ReplaceUnhealthyInstances { + delta.Add("Spec.ReplaceUnhealthyInstances", a.ko.Spec.ReplaceUnhealthyInstances, b.ko.Spec.ReplaceUnhealthyInstances) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.SpotOptions, b.ko.Spec.SpotOptions) { + delta.Add("Spec.SpotOptions", a.ko.Spec.SpotOptions, b.ko.Spec.SpotOptions) + } else if a.ko.Spec.SpotOptions != nil && b.ko.Spec.SpotOptions != nil { + if ackcompare.HasNilDifference(a.ko.Spec.SpotOptions.AllocationStrategy, b.ko.Spec.SpotOptions.AllocationStrategy) { + delta.Add("Spec.SpotOptions.AllocationStrategy", a.ko.Spec.SpotOptions.AllocationStrategy, b.ko.Spec.SpotOptions.AllocationStrategy) + } else if a.ko.Spec.SpotOptions.AllocationStrategy != nil && b.ko.Spec.SpotOptions.AllocationStrategy != nil { + if *a.ko.Spec.SpotOptions.AllocationStrategy != *b.ko.Spec.SpotOptions.AllocationStrategy { + delta.Add("Spec.SpotOptions.AllocationStrategy", a.ko.Spec.SpotOptions.AllocationStrategy, b.ko.Spec.SpotOptions.AllocationStrategy) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.SpotOptions.InstanceInterruptionBehavior, b.ko.Spec.SpotOptions.InstanceInterruptionBehavior) { + delta.Add("Spec.SpotOptions.InstanceInterruptionBehavior", a.ko.Spec.SpotOptions.InstanceInterruptionBehavior, b.ko.Spec.SpotOptions.InstanceInterruptionBehavior) + } else if a.ko.Spec.SpotOptions.InstanceInterruptionBehavior != nil && b.ko.Spec.SpotOptions.InstanceInterruptionBehavior != nil { + if *a.ko.Spec.SpotOptions.InstanceInterruptionBehavior != *b.ko.Spec.SpotOptions.InstanceInterruptionBehavior { + delta.Add("Spec.SpotOptions.InstanceInterruptionBehavior", a.ko.Spec.SpotOptions.InstanceInterruptionBehavior, b.ko.Spec.SpotOptions.InstanceInterruptionBehavior) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.SpotOptions.InstancePoolsToUseCount, b.ko.Spec.SpotOptions.InstancePoolsToUseCount) { + delta.Add("Spec.SpotOptions.InstancePoolsToUseCount", a.ko.Spec.SpotOptions.InstancePoolsToUseCount, b.ko.Spec.SpotOptions.InstancePoolsToUseCount) + } else if a.ko.Spec.SpotOptions.InstancePoolsToUseCount != nil && b.ko.Spec.SpotOptions.InstancePoolsToUseCount != nil { + if *a.ko.Spec.SpotOptions.InstancePoolsToUseCount != *b.ko.Spec.SpotOptions.InstancePoolsToUseCount { + delta.Add("Spec.SpotOptions.InstancePoolsToUseCount", a.ko.Spec.SpotOptions.InstancePoolsToUseCount, b.ko.Spec.SpotOptions.InstancePoolsToUseCount) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.SpotOptions.MaintenanceStrategies, b.ko.Spec.SpotOptions.MaintenanceStrategies) { + delta.Add("Spec.SpotOptions.MaintenanceStrategies", a.ko.Spec.SpotOptions.MaintenanceStrategies, b.ko.Spec.SpotOptions.MaintenanceStrategies) + } else if a.ko.Spec.SpotOptions.MaintenanceStrategies != nil && b.ko.Spec.SpotOptions.MaintenanceStrategies != nil { + if ackcompare.HasNilDifference(a.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance, b.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance) { + delta.Add("Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance", a.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance, b.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance) + } else if a.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance != nil && b.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance != nil { + if ackcompare.HasNilDifference(a.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.ReplacementStrategy, b.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.ReplacementStrategy) { + delta.Add("Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.ReplacementStrategy", a.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.ReplacementStrategy, b.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.ReplacementStrategy) + } else if a.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.ReplacementStrategy != nil && b.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.ReplacementStrategy != nil { + if *a.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.ReplacementStrategy != *b.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.ReplacementStrategy { + delta.Add("Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.ReplacementStrategy", a.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.ReplacementStrategy, b.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.ReplacementStrategy) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.TerminationDelay, b.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.TerminationDelay) { + delta.Add("Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.TerminationDelay", a.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.TerminationDelay, b.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.TerminationDelay) + } else if a.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.TerminationDelay != nil && b.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.TerminationDelay != nil { + if *a.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.TerminationDelay != *b.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.TerminationDelay { + delta.Add("Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.TerminationDelay", a.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.TerminationDelay, b.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.TerminationDelay) + } + } + } + } + if ackcompare.HasNilDifference(a.ko.Spec.SpotOptions.MaxTotalPrice, b.ko.Spec.SpotOptions.MaxTotalPrice) { + delta.Add("Spec.SpotOptions.MaxTotalPrice", a.ko.Spec.SpotOptions.MaxTotalPrice, b.ko.Spec.SpotOptions.MaxTotalPrice) + } else if a.ko.Spec.SpotOptions.MaxTotalPrice != nil && b.ko.Spec.SpotOptions.MaxTotalPrice != nil { + if *a.ko.Spec.SpotOptions.MaxTotalPrice != *b.ko.Spec.SpotOptions.MaxTotalPrice { + delta.Add("Spec.SpotOptions.MaxTotalPrice", a.ko.Spec.SpotOptions.MaxTotalPrice, b.ko.Spec.SpotOptions.MaxTotalPrice) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.SpotOptions.MinTargetCapacity, b.ko.Spec.SpotOptions.MinTargetCapacity) { + delta.Add("Spec.SpotOptions.MinTargetCapacity", a.ko.Spec.SpotOptions.MinTargetCapacity, b.ko.Spec.SpotOptions.MinTargetCapacity) + } else if a.ko.Spec.SpotOptions.MinTargetCapacity != nil && b.ko.Spec.SpotOptions.MinTargetCapacity != nil { + if *a.ko.Spec.SpotOptions.MinTargetCapacity != *b.ko.Spec.SpotOptions.MinTargetCapacity { + delta.Add("Spec.SpotOptions.MinTargetCapacity", a.ko.Spec.SpotOptions.MinTargetCapacity, b.ko.Spec.SpotOptions.MinTargetCapacity) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.SpotOptions.SingleAvailabilityZone, b.ko.Spec.SpotOptions.SingleAvailabilityZone) { + delta.Add("Spec.SpotOptions.SingleAvailabilityZone", a.ko.Spec.SpotOptions.SingleAvailabilityZone, b.ko.Spec.SpotOptions.SingleAvailabilityZone) + } else if a.ko.Spec.SpotOptions.SingleAvailabilityZone != nil && b.ko.Spec.SpotOptions.SingleAvailabilityZone != nil { + if *a.ko.Spec.SpotOptions.SingleAvailabilityZone != *b.ko.Spec.SpotOptions.SingleAvailabilityZone { + delta.Add("Spec.SpotOptions.SingleAvailabilityZone", a.ko.Spec.SpotOptions.SingleAvailabilityZone, b.ko.Spec.SpotOptions.SingleAvailabilityZone) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.SpotOptions.SingleInstanceType, b.ko.Spec.SpotOptions.SingleInstanceType) { + delta.Add("Spec.SpotOptions.SingleInstanceType", a.ko.Spec.SpotOptions.SingleInstanceType, b.ko.Spec.SpotOptions.SingleInstanceType) + } else if a.ko.Spec.SpotOptions.SingleInstanceType != nil && b.ko.Spec.SpotOptions.SingleInstanceType != nil { + if *a.ko.Spec.SpotOptions.SingleInstanceType != *b.ko.Spec.SpotOptions.SingleInstanceType { + delta.Add("Spec.SpotOptions.SingleInstanceType", a.ko.Spec.SpotOptions.SingleInstanceType, b.ko.Spec.SpotOptions.SingleInstanceType) + } + } + } + desiredACKTags, _ := convertToOrderedACKTags(a.ko.Spec.Tags) + latestACKTags, _ := convertToOrderedACKTags(b.ko.Spec.Tags) + if !ackcompare.MapStringStringEqual(desiredACKTags, latestACKTags) { + delta.Add("Spec.Tags", a.ko.Spec.Tags, b.ko.Spec.Tags) + } + if ackcompare.HasNilDifference(a.ko.Spec.TargetCapacitySpecification, b.ko.Spec.TargetCapacitySpecification) { + delta.Add("Spec.TargetCapacitySpecification", a.ko.Spec.TargetCapacitySpecification, b.ko.Spec.TargetCapacitySpecification) + } else if a.ko.Spec.TargetCapacitySpecification != nil && b.ko.Spec.TargetCapacitySpecification != nil { + if ackcompare.HasNilDifference(a.ko.Spec.TargetCapacitySpecification.DefaultTargetCapacityType, b.ko.Spec.TargetCapacitySpecification.DefaultTargetCapacityType) { + delta.Add("Spec.TargetCapacitySpecification.DefaultTargetCapacityType", a.ko.Spec.TargetCapacitySpecification.DefaultTargetCapacityType, b.ko.Spec.TargetCapacitySpecification.DefaultTargetCapacityType) + } else if a.ko.Spec.TargetCapacitySpecification.DefaultTargetCapacityType != nil && b.ko.Spec.TargetCapacitySpecification.DefaultTargetCapacityType != nil { + if *a.ko.Spec.TargetCapacitySpecification.DefaultTargetCapacityType != *b.ko.Spec.TargetCapacitySpecification.DefaultTargetCapacityType { + delta.Add("Spec.TargetCapacitySpecification.DefaultTargetCapacityType", a.ko.Spec.TargetCapacitySpecification.DefaultTargetCapacityType, b.ko.Spec.TargetCapacitySpecification.DefaultTargetCapacityType) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.TargetCapacitySpecification.OnDemandTargetCapacity, b.ko.Spec.TargetCapacitySpecification.OnDemandTargetCapacity) { + delta.Add("Spec.TargetCapacitySpecification.OnDemandTargetCapacity", a.ko.Spec.TargetCapacitySpecification.OnDemandTargetCapacity, b.ko.Spec.TargetCapacitySpecification.OnDemandTargetCapacity) + } else if a.ko.Spec.TargetCapacitySpecification.OnDemandTargetCapacity != nil && b.ko.Spec.TargetCapacitySpecification.OnDemandTargetCapacity != nil { + if *a.ko.Spec.TargetCapacitySpecification.OnDemandTargetCapacity != *b.ko.Spec.TargetCapacitySpecification.OnDemandTargetCapacity { + delta.Add("Spec.TargetCapacitySpecification.OnDemandTargetCapacity", a.ko.Spec.TargetCapacitySpecification.OnDemandTargetCapacity, b.ko.Spec.TargetCapacitySpecification.OnDemandTargetCapacity) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.TargetCapacitySpecification.SpotTargetCapacity, b.ko.Spec.TargetCapacitySpecification.SpotTargetCapacity) { + delta.Add("Spec.TargetCapacitySpecification.SpotTargetCapacity", a.ko.Spec.TargetCapacitySpecification.SpotTargetCapacity, b.ko.Spec.TargetCapacitySpecification.SpotTargetCapacity) + } else if a.ko.Spec.TargetCapacitySpecification.SpotTargetCapacity != nil && b.ko.Spec.TargetCapacitySpecification.SpotTargetCapacity != nil { + if *a.ko.Spec.TargetCapacitySpecification.SpotTargetCapacity != *b.ko.Spec.TargetCapacitySpecification.SpotTargetCapacity { + delta.Add("Spec.TargetCapacitySpecification.SpotTargetCapacity", a.ko.Spec.TargetCapacitySpecification.SpotTargetCapacity, b.ko.Spec.TargetCapacitySpecification.SpotTargetCapacity) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.TargetCapacitySpecification.TargetCapacityUnitType, b.ko.Spec.TargetCapacitySpecification.TargetCapacityUnitType) { + delta.Add("Spec.TargetCapacitySpecification.TargetCapacityUnitType", a.ko.Spec.TargetCapacitySpecification.TargetCapacityUnitType, b.ko.Spec.TargetCapacitySpecification.TargetCapacityUnitType) + } else if a.ko.Spec.TargetCapacitySpecification.TargetCapacityUnitType != nil && b.ko.Spec.TargetCapacitySpecification.TargetCapacityUnitType != nil { + if *a.ko.Spec.TargetCapacitySpecification.TargetCapacityUnitType != *b.ko.Spec.TargetCapacitySpecification.TargetCapacityUnitType { + delta.Add("Spec.TargetCapacitySpecification.TargetCapacityUnitType", a.ko.Spec.TargetCapacitySpecification.TargetCapacityUnitType, b.ko.Spec.TargetCapacitySpecification.TargetCapacityUnitType) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.TargetCapacitySpecification.TotalTargetCapacity, b.ko.Spec.TargetCapacitySpecification.TotalTargetCapacity) { + delta.Add("Spec.TargetCapacitySpecification.TotalTargetCapacity", a.ko.Spec.TargetCapacitySpecification.TotalTargetCapacity, b.ko.Spec.TargetCapacitySpecification.TotalTargetCapacity) + } else if a.ko.Spec.TargetCapacitySpecification.TotalTargetCapacity != nil && b.ko.Spec.TargetCapacitySpecification.TotalTargetCapacity != nil { + if *a.ko.Spec.TargetCapacitySpecification.TotalTargetCapacity != *b.ko.Spec.TargetCapacitySpecification.TotalTargetCapacity { + delta.Add("Spec.TargetCapacitySpecification.TotalTargetCapacity", a.ko.Spec.TargetCapacitySpecification.TotalTargetCapacity, b.ko.Spec.TargetCapacitySpecification.TotalTargetCapacity) + } + } + } + if ackcompare.HasNilDifference(a.ko.Spec.TerminateInstancesOnDeletion, b.ko.Spec.TerminateInstancesOnDeletion) { + delta.Add("Spec.TerminateInstancesOnDeletion", a.ko.Spec.TerminateInstancesOnDeletion, b.ko.Spec.TerminateInstancesOnDeletion) + } else if a.ko.Spec.TerminateInstancesOnDeletion != nil && b.ko.Spec.TerminateInstancesOnDeletion != nil { + if *a.ko.Spec.TerminateInstancesOnDeletion != *b.ko.Spec.TerminateInstancesOnDeletion { + delta.Add("Spec.TerminateInstancesOnDeletion", a.ko.Spec.TerminateInstancesOnDeletion, b.ko.Spec.TerminateInstancesOnDeletion) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.TerminateInstancesWithExpiration, b.ko.Spec.TerminateInstancesWithExpiration) { + delta.Add("Spec.TerminateInstancesWithExpiration", a.ko.Spec.TerminateInstancesWithExpiration, b.ko.Spec.TerminateInstancesWithExpiration) + } else if a.ko.Spec.TerminateInstancesWithExpiration != nil && b.ko.Spec.TerminateInstancesWithExpiration != nil { + if *a.ko.Spec.TerminateInstancesWithExpiration != *b.ko.Spec.TerminateInstancesWithExpiration { + delta.Add("Spec.TerminateInstancesWithExpiration", a.ko.Spec.TerminateInstancesWithExpiration, b.ko.Spec.TerminateInstancesWithExpiration) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.Type, b.ko.Spec.Type) { + delta.Add("Spec.Type", a.ko.Spec.Type, b.ko.Spec.Type) + } else if a.ko.Spec.Type != nil && b.ko.Spec.Type != nil { + if *a.ko.Spec.Type != *b.ko.Spec.Type { + delta.Add("Spec.Type", a.ko.Spec.Type, b.ko.Spec.Type) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.ValidFrom, b.ko.Spec.ValidFrom) { + delta.Add("Spec.ValidFrom", a.ko.Spec.ValidFrom, b.ko.Spec.ValidFrom) + } else if a.ko.Spec.ValidFrom != nil && b.ko.Spec.ValidFrom != nil { + if !a.ko.Spec.ValidFrom.Equal(b.ko.Spec.ValidFrom) { + delta.Add("Spec.ValidFrom", a.ko.Spec.ValidFrom, b.ko.Spec.ValidFrom) + } + } + if ackcompare.HasNilDifference(a.ko.Spec.ValidUntil, b.ko.Spec.ValidUntil) { + delta.Add("Spec.ValidUntil", a.ko.Spec.ValidUntil, b.ko.Spec.ValidUntil) + } else if a.ko.Spec.ValidUntil != nil && b.ko.Spec.ValidUntil != nil { + if !a.ko.Spec.ValidUntil.Equal(b.ko.Spec.ValidUntil) { + delta.Add("Spec.ValidUntil", a.ko.Spec.ValidUntil, b.ko.Spec.ValidUntil) + } + } + + return delta +} diff --git a/pkg/resource/fleet/descriptor.go b/pkg/resource/fleet/descriptor.go new file mode 100644 index 00000000..6399fc70 --- /dev/null +++ b/pkg/resource/fleet/descriptor.go @@ -0,0 +1,155 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package fleet + +import ( + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + rtclient "sigs.k8s.io/controller-runtime/pkg/client" + k8sctrlutil "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + svcapitypes "github.com/aws-controllers-k8s/ec2-controller/apis/v1alpha1" +) + +const ( + FinalizerString = "finalizers.ec2.services.k8s.aws/Fleet" +) + +var ( + GroupVersionResource = svcapitypes.GroupVersion.WithResource("fleets") + GroupKind = metav1.GroupKind{ + Group: "ec2.services.k8s.aws", + Kind: "Fleet", + } +) + +// resourceDescriptor implements the +// `aws-service-operator-k8s/pkg/types.AWSResourceDescriptor` interface +type resourceDescriptor struct { +} + +// GroupVersionKind returns a Kubernetes schema.GroupVersionKind struct that +// describes the API Group, Version and Kind of CRs described by the descriptor +func (d *resourceDescriptor) GroupVersionKind() schema.GroupVersionKind { + return svcapitypes.GroupVersion.WithKind(GroupKind.Kind) +} + +// EmptyRuntimeObject returns an empty object prototype that may be used in +// apimachinery and k8s client operations +func (d *resourceDescriptor) EmptyRuntimeObject() rtclient.Object { + return &svcapitypes.Fleet{} +} + +// ResourceFromRuntimeObject returns an AWSResource that has been initialized +// with the supplied runtime.Object +func (d *resourceDescriptor) ResourceFromRuntimeObject( + obj rtclient.Object, +) acktypes.AWSResource { + return &resource{ + ko: obj.(*svcapitypes.Fleet), + } +} + +// Delta returns an `ackcompare.Delta` object containing the difference between +// one `AWSResource` and another. +func (d *resourceDescriptor) Delta(a, b acktypes.AWSResource) *ackcompare.Delta { + return newResourceDelta(a.(*resource), b.(*resource)) +} + +// IsManaged returns true if the supplied AWSResource is under the management +// of an ACK service controller. What this means in practice is that the +// underlying custom resource (CR) in the AWSResource has had a +// resource-specific finalizer associated with it. +func (d *resourceDescriptor) IsManaged( + res acktypes.AWSResource, +) bool { + obj := res.RuntimeObject() + if obj == nil { + // Should not happen. If it does, there is a bug in the code + panic("nil RuntimeMetaObject in AWSResource") + } + // Remove use of custom code once + // https://github.com/kubernetes-sigs/controller-runtime/issues/994 is + // fixed. This should be able to be: + // + // return k8sctrlutil.ContainsFinalizer(obj, FinalizerString) + return containsFinalizer(obj, FinalizerString) +} + +// Remove once https://github.com/kubernetes-sigs/controller-runtime/issues/994 +// is fixed. +func containsFinalizer(obj rtclient.Object, finalizer string) bool { + f := obj.GetFinalizers() + for _, e := range f { + if e == finalizer { + return true + } + } + return false +} + +// MarkManaged places the supplied resource under the management of ACK. What +// this typically means is that the resource manager will decorate the +// underlying custom resource (CR) with a finalizer that indicates ACK is +// managing the resource and the underlying CR may not be deleted until ACK is +// finished cleaning up any backend AWS service resources associated with the +// CR. +func (d *resourceDescriptor) MarkManaged( + res acktypes.AWSResource, +) { + obj := res.RuntimeObject() + if obj == nil { + // Should not happen. If it does, there is a bug in the code + panic("nil RuntimeMetaObject in AWSResource") + } + k8sctrlutil.AddFinalizer(obj, FinalizerString) +} + +// MarkUnmanaged removes the supplied resource from management by ACK. What +// this typically means is that the resource manager will remove a finalizer +// underlying custom resource (CR) that indicates ACK is managing the resource. +// This will allow the Kubernetes API server to delete the underlying CR. +func (d *resourceDescriptor) MarkUnmanaged( + res acktypes.AWSResource, +) { + obj := res.RuntimeObject() + if obj == nil { + // Should not happen. If it does, there is a bug in the code + panic("nil RuntimeMetaObject in AWSResource") + } + k8sctrlutil.RemoveFinalizer(obj, FinalizerString) +} + +// MarkAdopted places descriptors on the custom resource that indicate the +// resource was not created from within ACK. +func (d *resourceDescriptor) MarkAdopted( + res acktypes.AWSResource, +) { + obj := res.RuntimeObject() + if obj == nil { + // Should not happen. If it does, there is a bug in the code + panic("nil RuntimeObject in AWSResource") + } + curr := obj.GetAnnotations() + if curr == nil { + curr = make(map[string]string) + } + curr[ackv1alpha1.AnnotationAdopted] = "true" + obj.SetAnnotations(curr) +} diff --git a/pkg/resource/fleet/hooks.go b/pkg/resource/fleet/hooks.go new file mode 100644 index 00000000..a2ed4127 --- /dev/null +++ b/pkg/resource/fleet/hooks.go @@ -0,0 +1,115 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +package fleet + +import ( + "fmt" + "time" + + "github.com/aws-controllers-k8s/ec2-controller/pkg/tags" + ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" + ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue" + + svcsdk "github.com/aws/aws-sdk-go-v2/service/ec2" + svcsdktypes "github.com/aws/aws-sdk-go-v2/service/ec2/types" +) + +// updateTagSpecificationsInCreateRequest adds +// Tags defined in the Spec to CreateFleetInput.TagSpecification +// and ensures the ResourceType is always set to 'fleet' +func updateTagSpecificationsInCreateRequest(r *resource, + input *svcsdk.CreateFleetInput) { + input.TagSpecifications = nil + desiredTagSpecs := svcsdktypes.TagSpecification{} + if r.ko.Spec.Tags != nil { + requestedTags := []svcsdktypes.Tag{} + for _, desiredTag := range r.ko.Spec.Tags { + // Add in tags defined in the Spec + tag := svcsdktypes.Tag{} + if desiredTag.Key != nil && desiredTag.Value != nil { + tag.Key = desiredTag.Key + tag.Value = desiredTag.Value + } + requestedTags = append(requestedTags, tag) + } + desiredTagSpecs.ResourceType = "fleet" + desiredTagSpecs.Tags = requestedTags + input.TagSpecifications = []svcsdktypes.TagSpecification{desiredTagSpecs} + } +} + +var syncTags = tags.Sync + +var computeTagsDelta = tags.ComputeTagsDelta + +var ( + ErrFleetDeleting = fmt.Errorf( + "Fleet in '%v/%v' state, cannot be modified or deleted", + svcsdktypes.FleetStateCodeDeletedTerminatingInstances, svcsdktypes.FleetStateCodeDeletedRunning, + ) + requeueWaitWhileDeleting = ackrequeue.NeededAfter( + ErrFleetDeleting, + 5*time.Second, + ) +) + +// addIDToDeleteRequest adds resource's Fleet ID to DeleteRequest. +// Return error to indicate to callers that the resource is not yet created. +func addIDToDeleteRequest(r *resource, + input *svcsdk.DeleteFleetsInput) error { + if r.ko.Status.FleetID == nil { + return fmt.Errorf("unable to extract FleetID from resource") + } + input.FleetIds = []string{*r.ko.Status.FleetID} + return nil +} + +// fleetDeleting returns true if the supplied Fleet is in the process +// of being deleted +func fleetDeleting(r *resource) bool { + if r.ko.Status.FleetState == nil { + return false + } + fleetState := *r.ko.Status.FleetState + if fleetState == string(svcsdktypes.FleetStateCodeDeletedTerminatingInstances) || fleetState == string(svcsdktypes.FleetStateCodeDeletedRunning) { + return true + } + return false +} + +// fleetDeleted checks if the Fleet is fully deleted +func fleetDeleted(r *resource) bool { + if r.ko.Status.FleetState == nil { + return false + } + + fleetState := *r.ko.Status.FleetState + return fleetState == string(svcsdktypes.FleetStateCodeDeleted) +} + +// If immutable fields are defined in AWS but not in spec, use AWS values +// This applies when adopting existing fleets +func customPreCompare( + delta *ackcompare.Delta, + a *resource, + b *resource, +) { + if a.ko.Spec.SpotOptions == nil { + a.ko.Spec.SpotOptions = b.ko.Spec.SpotOptions + } + if a.ko.Spec.OnDemandOptions == nil { + a.ko.Spec.OnDemandOptions = b.ko.Spec.OnDemandOptions + } + +} diff --git a/pkg/resource/fleet/identifiers.go b/pkg/resource/fleet/identifiers.go new file mode 100644 index 00000000..932c2a16 --- /dev/null +++ b/pkg/resource/fleet/identifiers.go @@ -0,0 +1,55 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package fleet + +import ( + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" +) + +// resourceIdentifiers implements the +// `aws-service-operator-k8s/pkg/types.AWSResourceIdentifiers` interface +type resourceIdentifiers struct { + meta *ackv1alpha1.ResourceMetadata +} + +// ARN returns the AWS Resource Name for the backend AWS resource. If nil, +// this means the resource has not yet been created in the backend AWS +// service. +func (ri *resourceIdentifiers) ARN() *ackv1alpha1.AWSResourceName { + if ri.meta != nil { + return ri.meta.ARN + } + return nil +} + +// OwnerAccountID returns the AWS account identifier in which the +// backend AWS resource resides, or nil if this information is not known +// for the resource +func (ri *resourceIdentifiers) OwnerAccountID() *ackv1alpha1.AWSAccountID { + if ri.meta != nil { + return ri.meta.OwnerAccountID + } + return nil +} + +// Region returns the AWS region in which the resource exists, or +// nil if this information is not known. +func (ri *resourceIdentifiers) Region() *ackv1alpha1.AWSRegion { + if ri.meta != nil { + return ri.meta.Region + } + return nil +} diff --git a/pkg/resource/fleet/manager.go b/pkg/resource/fleet/manager.go new file mode 100644 index 00000000..555a520b --- /dev/null +++ b/pkg/resource/fleet/manager.go @@ -0,0 +1,468 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package fleet + +import ( + "context" + "fmt" + "time" + + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" + ackcondition "github.com/aws-controllers-k8s/runtime/pkg/condition" + ackcfg "github.com/aws-controllers-k8s/runtime/pkg/config" + ackerr "github.com/aws-controllers-k8s/runtime/pkg/errors" + ackmetrics "github.com/aws-controllers-k8s/runtime/pkg/metrics" + ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue" + ackrt "github.com/aws-controllers-k8s/runtime/pkg/runtime" + ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log" + acktags "github.com/aws-controllers-k8s/runtime/pkg/tags" + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + ackutil "github.com/aws-controllers-k8s/runtime/pkg/util" + "github.com/aws/aws-sdk-go-v2/aws" + svcsdk "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" + + svcapitypes "github.com/aws-controllers-k8s/ec2-controller/apis/v1alpha1" +) + +var ( + _ = ackutil.InStrings + _ = acktags.NewTags() + _ = ackrt.MissingImageTagValue + _ = svcapitypes.Fleet{} +) + +// +kubebuilder:rbac:groups=ec2.services.k8s.aws,resources=fleets,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=ec2.services.k8s.aws,resources=fleets/status,verbs=get;update;patch + +var lateInitializeFieldNames = []string{"ExcessCapacityTerminationPolicy", "OnDemandOptions", "ReplaceUnhealthyInstances", "SpotOptions", "TargetCapacitySpecification.OnDemandTargetCapacity", "TargetCapacitySpecification.SpotTargetCapacity", "TerminateInstancesWithExpiration", "Type", "ValidFrom", "ValidUntil"} + +// resourceManager is responsible for providing a consistent way to perform +// CRUD operations in a backend AWS service API for Book custom resources. +type resourceManager struct { + // cfg is a copy of the ackcfg.Config object passed on start of the service + // controller + cfg ackcfg.Config + // clientcfg is a copy of the client configuration passed on start of the + // service controller + clientcfg aws.Config + // log refers to the logr.Logger object handling logging for the service + // controller + log logr.Logger + // metrics contains a collection of Prometheus metric objects that the + // service controller and its reconcilers track + metrics *ackmetrics.Metrics + // rr is the Reconciler which can be used for various utility + // functions such as querying for Secret values given a SecretReference + rr acktypes.Reconciler + // awsAccountID is the AWS account identifier that contains the resources + // managed by this resource manager + awsAccountID ackv1alpha1.AWSAccountID + // The AWS Region that this resource manager targets + awsRegion ackv1alpha1.AWSRegion + // sdk is a pointer to the AWS service API client exposed by the + // aws-sdk-go-v2/services/{alias} package. + sdkapi *svcsdk.Client +} + +// concreteResource returns a pointer to a resource from the supplied +// generic AWSResource interface +func (rm *resourceManager) concreteResource( + res acktypes.AWSResource, +) *resource { + // cast the generic interface into a pointer type specific to the concrete + // implementing resource type managed by this resource manager + return res.(*resource) +} + +// ReadOne returns the currently-observed state of the supplied AWSResource in +// the backend AWS service API. +func (rm *resourceManager) ReadOne( + ctx context.Context, + res acktypes.AWSResource, +) (acktypes.AWSResource, error) { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's ReadOne() method received resource with nil CR object") + } + observed, err := rm.sdkFind(ctx, r) + mirrorAWSTags(r, observed) + if err != nil { + if observed != nil { + return rm.onError(observed, err) + } + return rm.onError(r, err) + } + return rm.onSuccess(observed) +} + +// Create attempts to create the supplied AWSResource in the backend AWS +// service API, returning an AWSResource representing the newly-created +// resource +func (rm *resourceManager) Create( + ctx context.Context, + res acktypes.AWSResource, +) (acktypes.AWSResource, error) { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's Create() method received resource with nil CR object") + } + created, err := rm.sdkCreate(ctx, r) + if err != nil { + if created != nil { + return rm.onError(created, err) + } + return rm.onError(r, err) + } + return rm.onSuccess(created) +} + +// Update attempts to mutate the supplied desired AWSResource in the backend AWS +// service API, returning an AWSResource representing the newly-mutated +// resource. +// Note for specialized logic implementers can check to see how the latest +// observed resource differs from the supplied desired state. The +// higher-level reonciler determines whether or not the desired differs +// from the latest observed and decides whether to call the resource +// manager's Update method +func (rm *resourceManager) Update( + ctx context.Context, + resDesired acktypes.AWSResource, + resLatest acktypes.AWSResource, + delta *ackcompare.Delta, +) (acktypes.AWSResource, error) { + desired := rm.concreteResource(resDesired) + latest := rm.concreteResource(resLatest) + if desired.ko == nil || latest.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's Update() method received resource with nil CR object") + } + updated, err := rm.sdkUpdate(ctx, desired, latest, delta) + if err != nil { + if updated != nil { + return rm.onError(updated, err) + } + return rm.onError(latest, err) + } + return rm.onSuccess(updated) +} + +// Delete attempts to destroy the supplied AWSResource in the backend AWS +// service API, returning an AWSResource representing the +// resource being deleted (if delete is asynchronous and takes time) +func (rm *resourceManager) Delete( + ctx context.Context, + res acktypes.AWSResource, +) (acktypes.AWSResource, error) { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's Update() method received resource with nil CR object") + } + observed, err := rm.sdkDelete(ctx, r) + if err != nil { + if observed != nil { + return rm.onError(observed, err) + } + return rm.onError(r, err) + } + + return rm.onSuccess(observed) +} + +// ARNFromName returns an AWS Resource Name from a given string name. This +// is useful for constructing ARNs for APIs that require ARNs in their +// GetAttributes operations but all we have (for new CRs at least) is a +// name for the resource +func (rm *resourceManager) ARNFromName(name string) string { + return fmt.Sprintf( + "arn:aws:ec2:%s:%s:%s", + rm.awsRegion, + rm.awsAccountID, + name, + ) +} + +// LateInitialize returns an acktypes.AWSResource after setting the late initialized +// fields from the readOne call. This method will initialize the optional fields +// which were not provided by the k8s user but were defaulted by the AWS service. +// If there are no such fields to be initialized, the returned object is similar to +// object passed in the parameter. +func (rm *resourceManager) LateInitialize( + ctx context.Context, + latest acktypes.AWSResource, +) (acktypes.AWSResource, error) { + rlog := ackrtlog.FromContext(ctx) + // If there are no fields to late initialize, do nothing + if len(lateInitializeFieldNames) == 0 { + rlog.Debug("no late initialization required.") + return latest, nil + } + latestCopy := latest.DeepCopy() + lateInitConditionReason := "" + lateInitConditionMessage := "" + observed, err := rm.ReadOne(ctx, latestCopy) + if err != nil { + lateInitConditionMessage = "Unable to complete Read operation required for late initialization" + lateInitConditionReason = "Late Initialization Failure" + ackcondition.SetLateInitialized(latestCopy, corev1.ConditionFalse, &lateInitConditionMessage, &lateInitConditionReason) + ackcondition.SetSynced(latestCopy, corev1.ConditionFalse, nil, nil) + return latestCopy, err + } + lateInitializedRes := rm.lateInitializeFromReadOneOutput(observed, latestCopy) + incompleteInitialization := rm.incompleteLateInitialization(lateInitializedRes) + if incompleteInitialization { + // Add the condition with LateInitialized=False + lateInitConditionMessage = "Late initialization did not complete, requeuing with delay of 5 seconds" + lateInitConditionReason = "Delayed Late Initialization" + ackcondition.SetLateInitialized(lateInitializedRes, corev1.ConditionFalse, &lateInitConditionMessage, &lateInitConditionReason) + ackcondition.SetSynced(lateInitializedRes, corev1.ConditionFalse, nil, nil) + return lateInitializedRes, ackrequeue.NeededAfter(nil, time.Duration(5)*time.Second) + } + // Set LateInitialized condition to True + lateInitConditionMessage = "Late initialization successful" + lateInitConditionReason = "Late initialization successful" + ackcondition.SetLateInitialized(lateInitializedRes, corev1.ConditionTrue, &lateInitConditionMessage, &lateInitConditionReason) + return lateInitializedRes, nil +} + +// incompleteLateInitialization return true if there are fields which were supposed to be +// late initialized but are not. If all the fields are late initialized, false is returned +func (rm *resourceManager) incompleteLateInitialization( + res acktypes.AWSResource, +) bool { + return false +} + +// lateInitializeFromReadOneOutput late initializes the 'latest' resource from the 'observed' +// resource and returns 'latest' resource +func (rm *resourceManager) lateInitializeFromReadOneOutput( + observed acktypes.AWSResource, + latest acktypes.AWSResource, +) acktypes.AWSResource { + observedKo := rm.concreteResource(observed).ko.DeepCopy() + latestKo := rm.concreteResource(latest).ko.DeepCopy() + if observedKo.Spec.ExcessCapacityTerminationPolicy != nil && latestKo.Spec.ExcessCapacityTerminationPolicy == nil { + latestKo.Spec.ExcessCapacityTerminationPolicy = observedKo.Spec.ExcessCapacityTerminationPolicy + } + if observedKo.Spec.OnDemandOptions != nil && latestKo.Spec.OnDemandOptions == nil { + latestKo.Spec.OnDemandOptions = observedKo.Spec.OnDemandOptions + } + if observedKo.Spec.ReplaceUnhealthyInstances != nil && latestKo.Spec.ReplaceUnhealthyInstances == nil { + latestKo.Spec.ReplaceUnhealthyInstances = observedKo.Spec.ReplaceUnhealthyInstances + } + if observedKo.Spec.SpotOptions != nil && latestKo.Spec.SpotOptions == nil { + latestKo.Spec.SpotOptions = observedKo.Spec.SpotOptions + } + if observedKo.Spec.TargetCapacitySpecification != nil && latestKo.Spec.TargetCapacitySpecification != nil { + if observedKo.Spec.TargetCapacitySpecification.OnDemandTargetCapacity != nil && latestKo.Spec.TargetCapacitySpecification.OnDemandTargetCapacity == nil { + latestKo.Spec.TargetCapacitySpecification.OnDemandTargetCapacity = observedKo.Spec.TargetCapacitySpecification.OnDemandTargetCapacity + } + } + if observedKo.Spec.TargetCapacitySpecification != nil && latestKo.Spec.TargetCapacitySpecification != nil { + if observedKo.Spec.TargetCapacitySpecification.SpotTargetCapacity != nil && latestKo.Spec.TargetCapacitySpecification.SpotTargetCapacity == nil { + latestKo.Spec.TargetCapacitySpecification.SpotTargetCapacity = observedKo.Spec.TargetCapacitySpecification.SpotTargetCapacity + } + } + if observedKo.Spec.TerminateInstancesWithExpiration != nil && latestKo.Spec.TerminateInstancesWithExpiration == nil { + latestKo.Spec.TerminateInstancesWithExpiration = observedKo.Spec.TerminateInstancesWithExpiration + } + if observedKo.Spec.Type != nil && latestKo.Spec.Type == nil { + latestKo.Spec.Type = observedKo.Spec.Type + } + if observedKo.Spec.ValidFrom != nil && latestKo.Spec.ValidFrom == nil { + latestKo.Spec.ValidFrom = observedKo.Spec.ValidFrom + } + if observedKo.Spec.ValidUntil != nil && latestKo.Spec.ValidUntil == nil { + latestKo.Spec.ValidUntil = observedKo.Spec.ValidUntil + } + return &resource{latestKo} +} + +// IsSynced returns true if the resource is synced. +func (rm *resourceManager) IsSynced(ctx context.Context, res acktypes.AWSResource) (bool, error) { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's IsSynced() method received resource with nil CR object") + } + + if r.ko.Status.ActivityStatus == nil { + return false, nil + } + activityStatusCandidates := []string{"fulfilled"} + if !ackutil.InStrings(*r.ko.Status.ActivityStatus, activityStatusCandidates) { + return false, nil + } + if r.ko.Status.FleetState == nil { + return false, nil + } + fleetStateCandidates := []string{"active"} + if !ackutil.InStrings(*r.ko.Status.FleetState, fleetStateCandidates) { + return false, nil + } + + return true, nil +} + +// EnsureTags ensures that tags are present inside the AWSResource. +// If the AWSResource does not have any existing resource tags, the 'tags' +// field is initialized and the controller tags are added. +// If the AWSResource has existing resource tags, then controller tags are +// added to the existing resource tags without overriding them. +// If the AWSResource does not support tags, only then the controller tags +// will not be added to the AWSResource. +func (rm *resourceManager) EnsureTags( + ctx context.Context, + res acktypes.AWSResource, + md acktypes.ServiceControllerMetadata, +) error { + r := rm.concreteResource(res) + if r.ko == nil { + // Should never happen... if it does, it's buggy code. + panic("resource manager's EnsureTags method received resource with nil CR object") + } + defaultTags := ackrt.GetDefaultTags(&rm.cfg, r.ko, md) + var existingTags []*svcapitypes.Tag + existingTags = r.ko.Spec.Tags + resourceTags, keyOrder := convertToOrderedACKTags(existingTags) + tags := acktags.Merge(resourceTags, defaultTags) + r.ko.Spec.Tags = fromACKTags(tags, keyOrder) + return nil +} + +// FilterSystemTags removes system-managed tags from the resource's tag collection +// to prevent the controller from attempting to manage them. This includes: +// - Tags with keys starting with "aws:" (AWS-managed system tags) +// - Tags specified via the --resource-tags startup flag (controller-level tags) +// - Tags injected by AWS services (e.g., CloudFormation, EKS, etc.) +// +// This filtering is essential because: +// 1. AWS services automatically add system tags that cannot be modified by users +// 2. Attempting to remove these tags would result in API errors +// 3. The controller should only manage user-defined tags, not system tags +// +// Must be called after each Read operation to ensure the resource state +// reflects only manageable tags. This prevents unnecessary update attempts +// and maintains consistency between desired and actual resource state. +// +// Example system tags that are filtered: +// - aws:cloudformation:stack-name (CloudFormation) +// - aws:eks:cluster-name (EKS) +// - services.k8s.aws/* (Kubernetes-managed) +func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource, systemTags []string) { + r := rm.concreteResource(res) + if r == nil || r.ko == nil { + return + } + var existingTags []*svcapitypes.Tag + existingTags = r.ko.Spec.Tags + resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) + ignoreSystemTags(resourceTags, systemTags) + r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) +} + +// mirrorAWSTags ensures that AWS tags are included in the desired resource +// if they are present in the latest resource. This will ensure that the +// aws tags are not present in a diff. The logic of the controller will +// ensure these tags aren't patched to the resource in the cluster, and +// will only be present to make sure we don't try to remove these tags. +// +// Although there are a lot of similarities between this function and +// EnsureTags, they are very much different. +// While EnsureTags tries to make sure the resource contains the controller +// tags, mirrowAWSTags tries to make sure tags injected by AWS are mirrored +// from the latest resoruce to the desired resource. +func mirrorAWSTags(a *resource, b *resource) { + if a == nil || a.ko == nil || b == nil || b.ko == nil { + return + } + var existingLatestTags []*svcapitypes.Tag + var existingDesiredTags []*svcapitypes.Tag + existingDesiredTags = a.ko.Spec.Tags + existingLatestTags = b.ko.Spec.Tags + desiredTags, desiredTagKeyOrder := convertToOrderedACKTags(existingDesiredTags) + latestTags, _ := convertToOrderedACKTags(existingLatestTags) + syncAWSTags(desiredTags, latestTags) + a.ko.Spec.Tags = fromACKTags(desiredTags, desiredTagKeyOrder) +} + +// newResourceManager returns a new struct implementing +// acktypes.AWSResourceManager +// This is for AWS-SDK-GO-V2 - Created newResourceManager With AWS sdk-Go-ClientV2 +func newResourceManager( + cfg ackcfg.Config, + clientcfg aws.Config, + log logr.Logger, + metrics *ackmetrics.Metrics, + rr acktypes.Reconciler, + id ackv1alpha1.AWSAccountID, + region ackv1alpha1.AWSRegion, +) (*resourceManager, error) { + return &resourceManager{ + cfg: cfg, + clientcfg: clientcfg, + log: log, + metrics: metrics, + rr: rr, + awsAccountID: id, + awsRegion: region, + sdkapi: svcsdk.NewFromConfig(clientcfg), + }, nil +} + +// onError updates resource conditions and returns updated resource +// it returns nil if no condition is updated. +func (rm *resourceManager) onError( + r *resource, + err error, +) (acktypes.AWSResource, error) { + if r == nil { + return nil, err + } + r1, updated := rm.updateConditions(r, false, err) + if !updated { + return r, err + } + for _, condition := range r1.Conditions() { + if condition.Type == ackv1alpha1.ConditionTypeTerminal && + condition.Status == corev1.ConditionTrue { + // resource is in Terminal condition + // return Terminal error + return r1, ackerr.Terminal + } + } + return r1, err +} + +// onSuccess updates resource conditions and returns updated resource +// it returns the supplied resource if no condition is updated. +func (rm *resourceManager) onSuccess( + r *resource, +) (acktypes.AWSResource, error) { + if r == nil { + return nil, nil + } + r1, updated := rm.updateConditions(r, true, nil) + if !updated { + return r, nil + } + return r1, nil +} diff --git a/pkg/resource/fleet/manager_factory.go b/pkg/resource/fleet/manager_factory.go new file mode 100644 index 00000000..c3ea2625 --- /dev/null +++ b/pkg/resource/fleet/manager_factory.go @@ -0,0 +1,100 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package fleet + +import ( + "fmt" + "sync" + + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcfg "github.com/aws-controllers-k8s/runtime/pkg/config" + ackmetrics "github.com/aws-controllers-k8s/runtime/pkg/metrics" + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/go-logr/logr" + + svcresource "github.com/aws-controllers-k8s/ec2-controller/pkg/resource" +) + +// resourceManagerFactory produces resourceManager objects. It implements the +// `types.AWSResourceManagerFactory` interface. +type resourceManagerFactory struct { + sync.RWMutex + // rmCache contains resource managers for a particular AWS account ID + rmCache map[string]*resourceManager +} + +// ResourcePrototype returns an AWSResource that resource managers produced by +// this factory will handle +func (f *resourceManagerFactory) ResourceDescriptor() acktypes.AWSResourceDescriptor { + return &resourceDescriptor{} +} + +// ManagerFor returns a resource manager object that can manage resources for a +// supplied AWS account +func (f *resourceManagerFactory) ManagerFor( + cfg ackcfg.Config, + clientcfg aws.Config, + log logr.Logger, + metrics *ackmetrics.Metrics, + rr acktypes.Reconciler, + id ackv1alpha1.AWSAccountID, + region ackv1alpha1.AWSRegion, + roleARN ackv1alpha1.AWSResourceName, +) (acktypes.AWSResourceManager, error) { + // We use the account ID, region, and role ARN to uniquely identify a + // resource manager. This helps us to avoid creating multiple resource + // managers for the same account/region/roleARN combination. + rmId := fmt.Sprintf("%s/%s/%s", id, region, roleARN) + f.RLock() + rm, found := f.rmCache[rmId] + f.RUnlock() + + if found { + return rm, nil + } + + f.Lock() + defer f.Unlock() + + rm, err := newResourceManager(cfg, clientcfg, log, metrics, rr, id, region) + if err != nil { + return nil, err + } + f.rmCache[rmId] = rm + return rm, nil +} + +// IsAdoptable returns true if the resource is able to be adopted +func (f *resourceManagerFactory) IsAdoptable() bool { + return true +} + +// RequeueOnSuccessSeconds returns true if the resource should be requeued after specified seconds +// Default is false which means resource will not be requeued after success. +func (f *resourceManagerFactory) RequeueOnSuccessSeconds() int { + return 0 +} + +func newResourceManagerFactory() *resourceManagerFactory { + return &resourceManagerFactory{ + rmCache: map[string]*resourceManager{}, + } +} + +func init() { + svcresource.RegisterManagerFactory(newResourceManagerFactory()) +} diff --git a/pkg/resource/fleet/references.go b/pkg/resource/fleet/references.go new file mode 100644 index 00000000..e40c8bd4 --- /dev/null +++ b/pkg/resource/fleet/references.go @@ -0,0 +1,57 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package fleet + +import ( + "context" + + "sigs.k8s.io/controller-runtime/pkg/client" + + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + + svcapitypes "github.com/aws-controllers-k8s/ec2-controller/apis/v1alpha1" +) + +// ClearResolvedReferences removes any reference values that were made +// concrete in the spec. It returns a copy of the input AWSResource which +// contains the original *Ref values, but none of their respective concrete +// values. +func (rm *resourceManager) ClearResolvedReferences(res acktypes.AWSResource) acktypes.AWSResource { + ko := rm.concreteResource(res).ko.DeepCopy() + + return &resource{ko} +} + +// ResolveReferences finds if there are any Reference field(s) present +// inside AWSResource passed in the parameter and attempts to resolve those +// reference field(s) into their respective target field(s). It returns a +// copy of the input AWSResource with resolved reference(s), a boolean which +// is set to true if the resource contains any references (regardless of if +// they are resolved successfully) and an error if the passed AWSResource's +// reference field(s) could not be resolved. +func (rm *resourceManager) ResolveReferences( + ctx context.Context, + apiReader client.Reader, + res acktypes.AWSResource, +) (acktypes.AWSResource, bool, error) { + return res, false, nil +} + +// validateReferenceFields validates the reference field and corresponding +// identifier field. +func validateReferenceFields(ko *svcapitypes.Fleet) error { + return nil +} diff --git a/pkg/resource/fleet/resource.go b/pkg/resource/fleet/resource.go new file mode 100644 index 00000000..03b3dfbd --- /dev/null +++ b/pkg/resource/fleet/resource.go @@ -0,0 +1,113 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package fleet + +import ( + "fmt" + + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackerrors "github.com/aws-controllers-k8s/runtime/pkg/errors" + acktypes "github.com/aws-controllers-k8s/runtime/pkg/types" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + rtclient "sigs.k8s.io/controller-runtime/pkg/client" + + svcapitypes "github.com/aws-controllers-k8s/ec2-controller/apis/v1alpha1" +) + +// Hack to avoid import errors during build... +var ( + _ = &ackerrors.MissingNameIdentifier +) + +// resource implements the `aws-controller-k8s/runtime/pkg/types.AWSResource` +// interface +type resource struct { + // The Kubernetes-native CR representing the resource + ko *svcapitypes.Fleet +} + +// Identifiers returns an AWSResourceIdentifiers object containing various +// identifying information, including the AWS account ID that owns the +// resource, the resource's AWS Resource Name (ARN) +func (r *resource) Identifiers() acktypes.AWSResourceIdentifiers { + return &resourceIdentifiers{r.ko.Status.ACKResourceMetadata} +} + +// IsBeingDeleted returns true if the Kubernetes resource has a non-zero +// deletion timestamp +func (r *resource) IsBeingDeleted() bool { + return !r.ko.DeletionTimestamp.IsZero() +} + +// RuntimeObject returns the Kubernetes apimachinery/runtime representation of +// the AWSResource +func (r *resource) RuntimeObject() rtclient.Object { + return r.ko +} + +// MetaObject returns the Kubernetes apimachinery/apis/meta/v1.Object +// representation of the AWSResource +func (r *resource) MetaObject() metav1.Object { + return r.ko.GetObjectMeta() +} + +// Conditions returns the ACK Conditions collection for the AWSResource +func (r *resource) Conditions() []*ackv1alpha1.Condition { + return r.ko.Status.Conditions +} + +// ReplaceConditions sets the Conditions status field for the resource +func (r *resource) ReplaceConditions(conditions []*ackv1alpha1.Condition) { + r.ko.Status.Conditions = conditions +} + +// SetObjectMeta sets the ObjectMeta field for the resource +func (r *resource) SetObjectMeta(meta metav1.ObjectMeta) { + r.ko.ObjectMeta = meta +} + +// SetStatus will set the Status field for the resource +func (r *resource) SetStatus(desired acktypes.AWSResource) { + r.ko.Status = desired.(*resource).ko.Status +} + +// SetIdentifiers sets the Spec or Status field that is referenced as the unique +// resource identifier +func (r *resource) SetIdentifiers(identifier *ackv1alpha1.AWSIdentifiers) error { + if identifier.NameOrID == "" { + return ackerrors.MissingNameIdentifier + } + r.ko.Status.FleetID = &identifier.NameOrID + + return nil +} + +// PopulateResourceFromAnnotation populates the fields passed from adoption annotation +func (r *resource) PopulateResourceFromAnnotation(fields map[string]string) error { + primaryKey, ok := fields["fleetID"] + if !ok { + return ackerrors.NewTerminalError(fmt.Errorf("required field missing: fleetID")) + } + r.ko.Status.FleetID = &primaryKey + + return nil +} + +// DeepCopy will return a copy of the resource +func (r *resource) DeepCopy() acktypes.AWSResource { + koCopy := r.ko.DeepCopy() + return &resource{koCopy} +} diff --git a/pkg/resource/fleet/sdk.go b/pkg/resource/fleet/sdk.go new file mode 100644 index 00000000..d3f7d71d --- /dev/null +++ b/pkg/resource/fleet/sdk.go @@ -0,0 +1,2621 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package fleet + +import ( + "context" + "errors" + "fmt" + "math" + "reflect" + "strconv" + "strings" + + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare" + ackcondition "github.com/aws-controllers-k8s/runtime/pkg/condition" + ackerr "github.com/aws-controllers-k8s/runtime/pkg/errors" + ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue" + ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log" + "github.com/aws/aws-sdk-go-v2/aws" + svcsdk "github.com/aws/aws-sdk-go-v2/service/ec2" + svcsdktypes "github.com/aws/aws-sdk-go-v2/service/ec2/types" + smithy "github.com/aws/smithy-go" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + svcapitypes "github.com/aws-controllers-k8s/ec2-controller/apis/v1alpha1" +) + +// Hack to avoid import errors during build... +var ( + _ = &metav1.Time{} + _ = strings.ToLower("") + _ = &svcsdk.Client{} + _ = &svcapitypes.Fleet{} + _ = ackv1alpha1.AWSAccountID("") + _ = &ackerr.NotFound + _ = &ackcondition.NotManagedMessage + _ = &reflect.Value{} + _ = fmt.Sprintf("") + _ = &ackrequeue.NoRequeue{} + _ = &aws.Config{} +) + +// sdkFind returns SDK-specific information about a supplied resource +func (rm *resourceManager) sdkFind( + ctx context.Context, + r *resource, +) (latest *resource, err error) { + rlog := ackrtlog.FromContext(ctx) + exit := rlog.Trace("rm.sdkFind") + defer func() { + exit(err) + }() + // If any required fields in the input shape are missing, AWS resource is + // not created yet. Return NotFound here to indicate to callers that the + // resource isn't yet created. + if rm.requiredFieldsMissingFromReadManyInput(r) { + return nil, ackerr.NotFound + } + + input, err := rm.newListRequestPayload(r) + if err != nil { + return nil, err + } + var resp *svcsdk.DescribeFleetsOutput + resp, err = rm.sdkapi.DescribeFleets(ctx, input) + rm.metrics.RecordAPICall("READ_MANY", "DescribeFleets", err) + if err != nil { + var awsErr smithy.APIError + if errors.As(err, &awsErr) && awsErr.ErrorCode() == "UNKNOWN" { + return nil, ackerr.NotFound + } + return nil, err + } + + // Merge in the information we read from the API call above to the copy of + // the original Kubernetes object we passed to the function + ko := r.ko.DeepCopy() + + found := false + for _, elem := range resp.Fleets { + if elem.ActivityStatus != "" { + ko.Status.ActivityStatus = aws.String(string(elem.ActivityStatus)) + } else { + ko.Status.ActivityStatus = nil + } + if elem.Context != nil { + ko.Spec.Context = elem.Context + } else { + ko.Spec.Context = nil + } + if elem.Errors != nil { + f4 := []*svcapitypes.CreateFleetError{} + for _, f4iter := range elem.Errors { + f4elem := &svcapitypes.CreateFleetError{} + if f4iter.ErrorCode != nil { + f4elem.ErrorCode = f4iter.ErrorCode + } + if f4iter.ErrorMessage != nil { + f4elem.ErrorMessage = f4iter.ErrorMessage + } + if f4iter.LaunchTemplateAndOverrides != nil { + f4elemf2 := &svcapitypes.LaunchTemplateAndOverridesResponse{} + if f4iter.LaunchTemplateAndOverrides.LaunchTemplateSpecification != nil { + f4elemf2f0 := &svcapitypes.FleetLaunchTemplateSpecification{} + if f4iter.LaunchTemplateAndOverrides.LaunchTemplateSpecification.LaunchTemplateId != nil { + f4elemf2f0.LaunchTemplateID = f4iter.LaunchTemplateAndOverrides.LaunchTemplateSpecification.LaunchTemplateId + } + if f4iter.LaunchTemplateAndOverrides.LaunchTemplateSpecification.LaunchTemplateName != nil { + f4elemf2f0.LaunchTemplateName = f4iter.LaunchTemplateAndOverrides.LaunchTemplateSpecification.LaunchTemplateName + } + if f4iter.LaunchTemplateAndOverrides.LaunchTemplateSpecification.Version != nil { + f4elemf2f0.Version = f4iter.LaunchTemplateAndOverrides.LaunchTemplateSpecification.Version + } + f4elemf2.LaunchTemplateSpecification = f4elemf2f0 + } + if f4iter.LaunchTemplateAndOverrides.Overrides != nil { + f4elemf2f1 := &svcapitypes.FleetLaunchTemplateOverrides{} + if f4iter.LaunchTemplateAndOverrides.Overrides.AvailabilityZone != nil { + f4elemf2f1.AvailabilityZone = f4iter.LaunchTemplateAndOverrides.Overrides.AvailabilityZone + } + if f4iter.LaunchTemplateAndOverrides.Overrides.BlockDeviceMappings != nil { + f4elemf2f1f1 := []*svcapitypes.BlockDeviceMappingResponse{} + for _, f4elemf2f1f1iter := range f4iter.LaunchTemplateAndOverrides.Overrides.BlockDeviceMappings { + f4elemf2f1f1elem := &svcapitypes.BlockDeviceMappingResponse{} + if f4elemf2f1f1iter.DeviceName != nil { + f4elemf2f1f1elem.DeviceName = f4elemf2f1f1iter.DeviceName + } + if f4elemf2f1f1iter.Ebs != nil { + f4elemf2f1f1elemf1 := &svcapitypes.EBSBlockDeviceResponse{} + if f4elemf2f1f1iter.Ebs.DeleteOnTermination != nil { + f4elemf2f1f1elemf1.DeleteOnTermination = f4elemf2f1f1iter.Ebs.DeleteOnTermination + } + if f4elemf2f1f1iter.Ebs.Encrypted != nil { + f4elemf2f1f1elemf1.Encrypted = f4elemf2f1f1iter.Ebs.Encrypted + } + if f4elemf2f1f1iter.Ebs.Iops != nil { + iopsCopy := int64(*f4elemf2f1f1iter.Ebs.Iops) + f4elemf2f1f1elemf1.IOPS = &iopsCopy + } + if f4elemf2f1f1iter.Ebs.KmsKeyId != nil { + f4elemf2f1f1elemf1.KMSKeyID = f4elemf2f1f1iter.Ebs.KmsKeyId + } + if f4elemf2f1f1iter.Ebs.SnapshotId != nil { + f4elemf2f1f1elemf1.SnapshotID = f4elemf2f1f1iter.Ebs.SnapshotId + } + if f4elemf2f1f1iter.Ebs.Throughput != nil { + throughputCopy := int64(*f4elemf2f1f1iter.Ebs.Throughput) + f4elemf2f1f1elemf1.Throughput = &throughputCopy + } + if f4elemf2f1f1iter.Ebs.VolumeSize != nil { + volumeSizeCopy := int64(*f4elemf2f1f1iter.Ebs.VolumeSize) + f4elemf2f1f1elemf1.VolumeSize = &volumeSizeCopy + } + if f4elemf2f1f1iter.Ebs.VolumeType != "" { + f4elemf2f1f1elemf1.VolumeType = aws.String(string(f4elemf2f1f1iter.Ebs.VolumeType)) + } + f4elemf2f1f1elem.EBS = f4elemf2f1f1elemf1 + } + if f4elemf2f1f1iter.NoDevice != nil { + f4elemf2f1f1elem.NoDevice = f4elemf2f1f1iter.NoDevice + } + if f4elemf2f1f1iter.VirtualName != nil { + f4elemf2f1f1elem.VirtualName = f4elemf2f1f1iter.VirtualName + } + f4elemf2f1f1 = append(f4elemf2f1f1, f4elemf2f1f1elem) + } + f4elemf2f1.BlockDeviceMappings = f4elemf2f1f1 + } + if f4iter.LaunchTemplateAndOverrides.Overrides.ImageId != nil { + f4elemf2f1.ImageID = f4iter.LaunchTemplateAndOverrides.Overrides.ImageId + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements != nil { + f4elemf2f1f3 := &svcapitypes.InstanceRequirements{} + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorCount != nil { + f4elemf2f1f3f0 := &svcapitypes.AcceleratorCount{} + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorCount.Max != nil { + maxCopy := int64(*f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorCount.Max) + f4elemf2f1f3f0.Max = &maxCopy + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorCount.Min != nil { + minCopy := int64(*f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorCount.Min) + f4elemf2f1f3f0.Min = &minCopy + } + f4elemf2f1f3.AcceleratorCount = f4elemf2f1f3f0 + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorManufacturers != nil { + f4elemf2f1f3f1 := []*string{} + for _, f4elemf2f1f3f1iter := range f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorManufacturers { + var f4elemf2f1f3f1elem *string + f4elemf2f1f3f1elem = aws.String(string(f4elemf2f1f3f1iter)) + f4elemf2f1f3f1 = append(f4elemf2f1f3f1, f4elemf2f1f3f1elem) + } + f4elemf2f1f3.AcceleratorManufacturers = f4elemf2f1f3f1 + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorNames != nil { + f4elemf2f1f3f2 := []*string{} + for _, f4elemf2f1f3f2iter := range f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorNames { + var f4elemf2f1f3f2elem *string + f4elemf2f1f3f2elem = aws.String(string(f4elemf2f1f3f2iter)) + f4elemf2f1f3f2 = append(f4elemf2f1f3f2, f4elemf2f1f3f2elem) + } + f4elemf2f1f3.AcceleratorNames = f4elemf2f1f3f2 + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorTotalMemoryMiB != nil { + f4elemf2f1f3f3 := &svcapitypes.AcceleratorTotalMemoryMiB{} + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorTotalMemoryMiB.Max != nil { + maxCopy := int64(*f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorTotalMemoryMiB.Max) + f4elemf2f1f3f3.Max = &maxCopy + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorTotalMemoryMiB.Min != nil { + minCopy := int64(*f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorTotalMemoryMiB.Min) + f4elemf2f1f3f3.Min = &minCopy + } + f4elemf2f1f3.AcceleratorTotalMemoryMiB = f4elemf2f1f3f3 + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorTypes != nil { + f4elemf2f1f3f4 := []*string{} + for _, f4elemf2f1f3f4iter := range f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorTypes { + var f4elemf2f1f3f4elem *string + f4elemf2f1f3f4elem = aws.String(string(f4elemf2f1f3f4iter)) + f4elemf2f1f3f4 = append(f4elemf2f1f3f4, f4elemf2f1f3f4elem) + } + f4elemf2f1f3.AcceleratorTypes = f4elemf2f1f3f4 + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AllowedInstanceTypes != nil { + f4elemf2f1f3.AllowedInstanceTypes = aws.StringSlice(f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AllowedInstanceTypes) + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BareMetal != "" { + f4elemf2f1f3.BareMetal = aws.String(string(f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BareMetal)) + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BaselineEbsBandwidthMbps != nil { + f4elemf2f1f3f7 := &svcapitypes.BaselineEBSBandwidthMbps{} + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BaselineEbsBandwidthMbps.Max != nil { + maxCopy := int64(*f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BaselineEbsBandwidthMbps.Max) + f4elemf2f1f3f7.Max = &maxCopy + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BaselineEbsBandwidthMbps.Min != nil { + minCopy := int64(*f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BaselineEbsBandwidthMbps.Min) + f4elemf2f1f3f7.Min = &minCopy + } + f4elemf2f1f3.BaselineEBSBandwidthMbps = f4elemf2f1f3f7 + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BaselinePerformanceFactors != nil { + f4elemf2f1f3f8 := &svcapitypes.BaselinePerformanceFactors{} + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BaselinePerformanceFactors.Cpu != nil { + f4elemf2f1f3f8f0 := &svcapitypes.CPUPerformanceFactor{} + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BaselinePerformanceFactors.Cpu.References != nil { + f4elemf2f1f3f8f0f0 := []*svcapitypes.PerformanceFactorReference{} + for _, f4elemf2f1f3f8f0f0iter := range f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BaselinePerformanceFactors.Cpu.References { + f4elemf2f1f3f8f0f0elem := &svcapitypes.PerformanceFactorReference{} + if f4elemf2f1f3f8f0f0iter.InstanceFamily != nil { + f4elemf2f1f3f8f0f0elem.InstanceFamily = f4elemf2f1f3f8f0f0iter.InstanceFamily + } + f4elemf2f1f3f8f0f0 = append(f4elemf2f1f3f8f0f0, f4elemf2f1f3f8f0f0elem) + } + f4elemf2f1f3f8f0.References = f4elemf2f1f3f8f0f0 + } + f4elemf2f1f3f8.CPU = f4elemf2f1f3f8f0 + } + f4elemf2f1f3.BaselinePerformanceFactors = f4elemf2f1f3f8 + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BurstablePerformance != "" { + f4elemf2f1f3.BurstablePerformance = aws.String(string(f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BurstablePerformance)) + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.CpuManufacturers != nil { + f4elemf2f1f3f10 := []*string{} + for _, f4elemf2f1f3f10iter := range f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.CpuManufacturers { + var f4elemf2f1f3f10elem *string + f4elemf2f1f3f10elem = aws.String(string(f4elemf2f1f3f10iter)) + f4elemf2f1f3f10 = append(f4elemf2f1f3f10, f4elemf2f1f3f10elem) + } + f4elemf2f1f3.CPUManufacturers = f4elemf2f1f3f10 + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.ExcludedInstanceTypes != nil { + f4elemf2f1f3.ExcludedInstanceTypes = aws.StringSlice(f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.ExcludedInstanceTypes) + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.InstanceGenerations != nil { + f4elemf2f1f3f12 := []*string{} + for _, f4elemf2f1f3f12iter := range f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.InstanceGenerations { + var f4elemf2f1f3f12elem *string + f4elemf2f1f3f12elem = aws.String(string(f4elemf2f1f3f12iter)) + f4elemf2f1f3f12 = append(f4elemf2f1f3f12, f4elemf2f1f3f12elem) + } + f4elemf2f1f3.InstanceGenerations = f4elemf2f1f3f12 + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.LocalStorage != "" { + f4elemf2f1f3.LocalStorage = aws.String(string(f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.LocalStorage)) + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.LocalStorageTypes != nil { + f4elemf2f1f3f14 := []*string{} + for _, f4elemf2f1f3f14iter := range f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.LocalStorageTypes { + var f4elemf2f1f3f14elem *string + f4elemf2f1f3f14elem = aws.String(string(f4elemf2f1f3f14iter)) + f4elemf2f1f3f14 = append(f4elemf2f1f3f14, f4elemf2f1f3f14elem) + } + f4elemf2f1f3.LocalStorageTypes = f4elemf2f1f3f14 + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MaxSpotPriceAsPercentageOfOptimalOnDemandPrice != nil { + maxSpotPriceAsPercentageOfOptimalOnDemandPriceCopy := int64(*f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MaxSpotPriceAsPercentageOfOptimalOnDemandPrice) + f4elemf2f1f3.MaxSpotPriceAsPercentageOfOptimalOnDemandPrice = &maxSpotPriceAsPercentageOfOptimalOnDemandPriceCopy + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryGiBPerVCpu != nil { + f4elemf2f1f3f16 := &svcapitypes.MemoryGiBPerVCPU{} + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryGiBPerVCpu.Max != nil { + f4elemf2f1f3f16.Max = f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryGiBPerVCpu.Max + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryGiBPerVCpu.Min != nil { + f4elemf2f1f3f16.Min = f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryGiBPerVCpu.Min + } + f4elemf2f1f3.MemoryGiBPerVCPU = f4elemf2f1f3f16 + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryMiB != nil { + f4elemf2f1f3f17 := &svcapitypes.MemoryMiB{} + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryMiB.Max != nil { + maxCopy := int64(*f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryMiB.Max) + f4elemf2f1f3f17.Max = &maxCopy + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryMiB.Min != nil { + minCopy := int64(*f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryMiB.Min) + f4elemf2f1f3f17.Min = &minCopy + } + f4elemf2f1f3.MemoryMiB = f4elemf2f1f3f17 + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkBandwidthGbps != nil { + f4elemf2f1f3f18 := &svcapitypes.NetworkBandwidthGbps{} + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkBandwidthGbps.Max != nil { + f4elemf2f1f3f18.Max = f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkBandwidthGbps.Max + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkBandwidthGbps.Min != nil { + f4elemf2f1f3f18.Min = f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkBandwidthGbps.Min + } + f4elemf2f1f3.NetworkBandwidthGbps = f4elemf2f1f3f18 + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkInterfaceCount != nil { + f4elemf2f1f3f19 := &svcapitypes.NetworkInterfaceCount{} + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkInterfaceCount.Max != nil { + maxCopy := int64(*f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkInterfaceCount.Max) + f4elemf2f1f3f19.Max = &maxCopy + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkInterfaceCount.Min != nil { + minCopy := int64(*f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkInterfaceCount.Min) + f4elemf2f1f3f19.Min = &minCopy + } + f4elemf2f1f3.NetworkInterfaceCount = f4elemf2f1f3f19 + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.OnDemandMaxPricePercentageOverLowestPrice != nil { + onDemandMaxPricePercentageOverLowestPriceCopy := int64(*f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.OnDemandMaxPricePercentageOverLowestPrice) + f4elemf2f1f3.OnDemandMaxPricePercentageOverLowestPrice = &onDemandMaxPricePercentageOverLowestPriceCopy + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.RequireHibernateSupport != nil { + f4elemf2f1f3.RequireHibernateSupport = f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.RequireHibernateSupport + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.SpotMaxPricePercentageOverLowestPrice != nil { + spotMaxPricePercentageOverLowestPriceCopy := int64(*f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.SpotMaxPricePercentageOverLowestPrice) + f4elemf2f1f3.SpotMaxPricePercentageOverLowestPrice = &spotMaxPricePercentageOverLowestPriceCopy + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.TotalLocalStorageGB != nil { + f4elemf2f1f3f23 := &svcapitypes.TotalLocalStorageGB{} + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.TotalLocalStorageGB.Max != nil { + f4elemf2f1f3f23.Max = f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.TotalLocalStorageGB.Max + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.TotalLocalStorageGB.Min != nil { + f4elemf2f1f3f23.Min = f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.TotalLocalStorageGB.Min + } + f4elemf2f1f3.TotalLocalStorageGB = f4elemf2f1f3f23 + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.VCpuCount != nil { + f4elemf2f1f3f24 := &svcapitypes.VCPUCountRange{} + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.VCpuCount.Max != nil { + maxCopy := int64(*f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.VCpuCount.Max) + f4elemf2f1f3f24.Max = &maxCopy + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.VCpuCount.Min != nil { + minCopy := int64(*f4iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.VCpuCount.Min) + f4elemf2f1f3f24.Min = &minCopy + } + f4elemf2f1f3.VCPUCount = f4elemf2f1f3f24 + } + f4elemf2f1.InstanceRequirements = f4elemf2f1f3 + } + if f4iter.LaunchTemplateAndOverrides.Overrides.InstanceType != "" { + f4elemf2f1.InstanceType = aws.String(string(f4iter.LaunchTemplateAndOverrides.Overrides.InstanceType)) + } + if f4iter.LaunchTemplateAndOverrides.Overrides.MaxPrice != nil { + f4elemf2f1.MaxPrice = f4iter.LaunchTemplateAndOverrides.Overrides.MaxPrice + } + if f4iter.LaunchTemplateAndOverrides.Overrides.Placement != nil { + f4elemf2f1f6 := &svcapitypes.PlacementResponse{} + if f4iter.LaunchTemplateAndOverrides.Overrides.Placement.GroupName != nil { + f4elemf2f1f6.GroupName = f4iter.LaunchTemplateAndOverrides.Overrides.Placement.GroupName + } + f4elemf2f1.Placement = f4elemf2f1f6 + } + if f4iter.LaunchTemplateAndOverrides.Overrides.Priority != nil { + f4elemf2f1.Priority = f4iter.LaunchTemplateAndOverrides.Overrides.Priority + } + if f4iter.LaunchTemplateAndOverrides.Overrides.SubnetId != nil { + f4elemf2f1.SubnetID = f4iter.LaunchTemplateAndOverrides.Overrides.SubnetId + } + if f4iter.LaunchTemplateAndOverrides.Overrides.WeightedCapacity != nil { + f4elemf2f1.WeightedCapacity = f4iter.LaunchTemplateAndOverrides.Overrides.WeightedCapacity + } + f4elemf2.Overrides = f4elemf2f1 + } + f4elem.LaunchTemplateAndOverrides = f4elemf2 + } + if f4iter.Lifecycle != "" { + f4elem.Lifecycle = aws.String(string(f4iter.Lifecycle)) + } + f4 = append(f4, f4elem) + } + ko.Status.Errors = f4 + } else { + ko.Status.Errors = nil + } + if elem.ExcessCapacityTerminationPolicy != "" { + ko.Spec.ExcessCapacityTerminationPolicy = aws.String(string(elem.ExcessCapacityTerminationPolicy)) + } else { + ko.Spec.ExcessCapacityTerminationPolicy = nil + } + if elem.FleetId != nil { + ko.Status.FleetID = elem.FleetId + } else { + ko.Status.FleetID = nil + } + if elem.FleetState != "" { + ko.Status.FleetState = aws.String(string(elem.FleetState)) + } else { + ko.Status.FleetState = nil + } + if elem.FulfilledCapacity != nil { + ko.Status.FulfilledCapacity = elem.FulfilledCapacity + } else { + ko.Status.FulfilledCapacity = nil + } + if elem.LaunchTemplateConfigs != nil { + f11 := []*svcapitypes.FleetLaunchTemplateConfigRequest{} + for _, f11iter := range elem.LaunchTemplateConfigs { + f11elem := &svcapitypes.FleetLaunchTemplateConfigRequest{} + if f11iter.LaunchTemplateSpecification != nil { + f11elemf0 := &svcapitypes.FleetLaunchTemplateSpecificationRequest{} + if f11iter.LaunchTemplateSpecification.LaunchTemplateId != nil { + f11elemf0.LaunchTemplateID = f11iter.LaunchTemplateSpecification.LaunchTemplateId + } + if f11iter.LaunchTemplateSpecification.LaunchTemplateName != nil { + f11elemf0.LaunchTemplateName = f11iter.LaunchTemplateSpecification.LaunchTemplateName + } + if f11iter.LaunchTemplateSpecification.Version != nil { + f11elemf0.Version = f11iter.LaunchTemplateSpecification.Version + } + f11elem.LaunchTemplateSpecification = f11elemf0 + } + if f11iter.Overrides != nil { + f11elemf1 := []*svcapitypes.FleetLaunchTemplateOverridesRequest{} + for _, f11elemf1iter := range f11iter.Overrides { + f11elemf1elem := &svcapitypes.FleetLaunchTemplateOverridesRequest{} + if f11elemf1iter.AvailabilityZone != nil { + f11elemf1elem.AvailabilityZone = f11elemf1iter.AvailabilityZone + } + if f11elemf1iter.BlockDeviceMappings != nil { + f11elemf1elemf1 := []*svcapitypes.FleetBlockDeviceMappingRequest{} + for _, f11elemf1elemf1iter := range f11elemf1iter.BlockDeviceMappings { + f11elemf1elemf1elem := &svcapitypes.FleetBlockDeviceMappingRequest{} + if f11elemf1elemf1iter.DeviceName != nil { + f11elemf1elemf1elem.DeviceName = f11elemf1elemf1iter.DeviceName + } + if f11elemf1elemf1iter.Ebs != nil { + f11elemf1elemf1elemf1 := &svcapitypes.FleetEBSBlockDeviceRequest{} + if f11elemf1elemf1iter.Ebs.DeleteOnTermination != nil { + f11elemf1elemf1elemf1.DeleteOnTermination = f11elemf1elemf1iter.Ebs.DeleteOnTermination + } + if f11elemf1elemf1iter.Ebs.Encrypted != nil { + f11elemf1elemf1elemf1.Encrypted = f11elemf1elemf1iter.Ebs.Encrypted + } + if f11elemf1elemf1iter.Ebs.Iops != nil { + iopsCopy := int64(*f11elemf1elemf1iter.Ebs.Iops) + f11elemf1elemf1elemf1.IOPS = &iopsCopy + } + if f11elemf1elemf1iter.Ebs.KmsKeyId != nil { + f11elemf1elemf1elemf1.KMSKeyID = f11elemf1elemf1iter.Ebs.KmsKeyId + } + if f11elemf1elemf1iter.Ebs.SnapshotId != nil { + f11elemf1elemf1elemf1.SnapshotID = f11elemf1elemf1iter.Ebs.SnapshotId + } + if f11elemf1elemf1iter.Ebs.Throughput != nil { + throughputCopy := int64(*f11elemf1elemf1iter.Ebs.Throughput) + f11elemf1elemf1elemf1.Throughput = &throughputCopy + } + if f11elemf1elemf1iter.Ebs.VolumeSize != nil { + volumeSizeCopy := int64(*f11elemf1elemf1iter.Ebs.VolumeSize) + f11elemf1elemf1elemf1.VolumeSize = &volumeSizeCopy + } + if f11elemf1elemf1iter.Ebs.VolumeType != "" { + f11elemf1elemf1elemf1.VolumeType = aws.String(string(f11elemf1elemf1iter.Ebs.VolumeType)) + } + f11elemf1elemf1elem.EBS = f11elemf1elemf1elemf1 + } + if f11elemf1elemf1iter.NoDevice != nil { + f11elemf1elemf1elem.NoDevice = f11elemf1elemf1iter.NoDevice + } + if f11elemf1elemf1iter.VirtualName != nil { + f11elemf1elemf1elem.VirtualName = f11elemf1elemf1iter.VirtualName + } + f11elemf1elemf1 = append(f11elemf1elemf1, f11elemf1elemf1elem) + } + f11elemf1elem.BlockDeviceMappings = f11elemf1elemf1 + } + if f11elemf1iter.ImageId != nil { + f11elemf1elem.ImageID = f11elemf1iter.ImageId + } + if f11elemf1iter.InstanceRequirements != nil { + f11elemf1elemf3 := &svcapitypes.InstanceRequirementsRequest{} + if f11elemf1iter.InstanceRequirements.AcceleratorCount != nil { + f11elemf1elemf3f0 := &svcapitypes.AcceleratorCountRequest{} + if f11elemf1iter.InstanceRequirements.AcceleratorCount.Max != nil { + maxCopy := int64(*f11elemf1iter.InstanceRequirements.AcceleratorCount.Max) + f11elemf1elemf3f0.Max = &maxCopy + } + if f11elemf1iter.InstanceRequirements.AcceleratorCount.Min != nil { + minCopy := int64(*f11elemf1iter.InstanceRequirements.AcceleratorCount.Min) + f11elemf1elemf3f0.Min = &minCopy + } + f11elemf1elemf3.AcceleratorCount = f11elemf1elemf3f0 + } + if f11elemf1iter.InstanceRequirements.AcceleratorManufacturers != nil { + f11elemf1elemf3f1 := []*string{} + for _, f11elemf1elemf3f1iter := range f11elemf1iter.InstanceRequirements.AcceleratorManufacturers { + var f11elemf1elemf3f1elem *string + f11elemf1elemf3f1elem = aws.String(string(f11elemf1elemf3f1iter)) + f11elemf1elemf3f1 = append(f11elemf1elemf3f1, f11elemf1elemf3f1elem) + } + f11elemf1elemf3.AcceleratorManufacturers = f11elemf1elemf3f1 + } + if f11elemf1iter.InstanceRequirements.AcceleratorNames != nil { + f11elemf1elemf3f2 := []*string{} + for _, f11elemf1elemf3f2iter := range f11elemf1iter.InstanceRequirements.AcceleratorNames { + var f11elemf1elemf3f2elem *string + f11elemf1elemf3f2elem = aws.String(string(f11elemf1elemf3f2iter)) + f11elemf1elemf3f2 = append(f11elemf1elemf3f2, f11elemf1elemf3f2elem) + } + f11elemf1elemf3.AcceleratorNames = f11elemf1elemf3f2 + } + if f11elemf1iter.InstanceRequirements.AcceleratorTotalMemoryMiB != nil { + f11elemf1elemf3f3 := &svcapitypes.AcceleratorTotalMemoryMiBRequest{} + if f11elemf1iter.InstanceRequirements.AcceleratorTotalMemoryMiB.Max != nil { + maxCopy := int64(*f11elemf1iter.InstanceRequirements.AcceleratorTotalMemoryMiB.Max) + f11elemf1elemf3f3.Max = &maxCopy + } + if f11elemf1iter.InstanceRequirements.AcceleratorTotalMemoryMiB.Min != nil { + minCopy := int64(*f11elemf1iter.InstanceRequirements.AcceleratorTotalMemoryMiB.Min) + f11elemf1elemf3f3.Min = &minCopy + } + f11elemf1elemf3.AcceleratorTotalMemoryMiB = f11elemf1elemf3f3 + } + if f11elemf1iter.InstanceRequirements.AcceleratorTypes != nil { + f11elemf1elemf3f4 := []*string{} + for _, f11elemf1elemf3f4iter := range f11elemf1iter.InstanceRequirements.AcceleratorTypes { + var f11elemf1elemf3f4elem *string + f11elemf1elemf3f4elem = aws.String(string(f11elemf1elemf3f4iter)) + f11elemf1elemf3f4 = append(f11elemf1elemf3f4, f11elemf1elemf3f4elem) + } + f11elemf1elemf3.AcceleratorTypes = f11elemf1elemf3f4 + } + if f11elemf1iter.InstanceRequirements.AllowedInstanceTypes != nil { + f11elemf1elemf3.AllowedInstanceTypes = aws.StringSlice(f11elemf1iter.InstanceRequirements.AllowedInstanceTypes) + } + if f11elemf1iter.InstanceRequirements.BareMetal != "" { + f11elemf1elemf3.BareMetal = aws.String(string(f11elemf1iter.InstanceRequirements.BareMetal)) + } + if f11elemf1iter.InstanceRequirements.BaselineEbsBandwidthMbps != nil { + f11elemf1elemf3f7 := &svcapitypes.BaselineEBSBandwidthMbpsRequest{} + if f11elemf1iter.InstanceRequirements.BaselineEbsBandwidthMbps.Max != nil { + maxCopy := int64(*f11elemf1iter.InstanceRequirements.BaselineEbsBandwidthMbps.Max) + f11elemf1elemf3f7.Max = &maxCopy + } + if f11elemf1iter.InstanceRequirements.BaselineEbsBandwidthMbps.Min != nil { + minCopy := int64(*f11elemf1iter.InstanceRequirements.BaselineEbsBandwidthMbps.Min) + f11elemf1elemf3f7.Min = &minCopy + } + f11elemf1elemf3.BaselineEBSBandwidthMbps = f11elemf1elemf3f7 + } + if f11elemf1iter.InstanceRequirements.BaselinePerformanceFactors != nil { + f11elemf1elemf3f8 := &svcapitypes.BaselinePerformanceFactorsRequest{} + if f11elemf1iter.InstanceRequirements.BaselinePerformanceFactors.Cpu != nil { + f11elemf1elemf3f8f0 := &svcapitypes.CPUPerformanceFactorRequest{} + if f11elemf1iter.InstanceRequirements.BaselinePerformanceFactors.Cpu.References != nil { + f11elemf1elemf3f8f0f0 := []*svcapitypes.PerformanceFactorReferenceRequest{} + for _, f11elemf1elemf3f8f0f0iter := range f11elemf1iter.InstanceRequirements.BaselinePerformanceFactors.Cpu.References { + f11elemf1elemf3f8f0f0elem := &svcapitypes.PerformanceFactorReferenceRequest{} + if f11elemf1elemf3f8f0f0iter.InstanceFamily != nil { + f11elemf1elemf3f8f0f0elem.InstanceFamily = f11elemf1elemf3f8f0f0iter.InstanceFamily + } + f11elemf1elemf3f8f0f0 = append(f11elemf1elemf3f8f0f0, f11elemf1elemf3f8f0f0elem) + } + f11elemf1elemf3f8f0.References = f11elemf1elemf3f8f0f0 + } + f11elemf1elemf3f8.CPU = f11elemf1elemf3f8f0 + } + f11elemf1elemf3.BaselinePerformanceFactors = f11elemf1elemf3f8 + } + if f11elemf1iter.InstanceRequirements.BurstablePerformance != "" { + f11elemf1elemf3.BurstablePerformance = aws.String(string(f11elemf1iter.InstanceRequirements.BurstablePerformance)) + } + if f11elemf1iter.InstanceRequirements.CpuManufacturers != nil { + f11elemf1elemf3f10 := []*string{} + for _, f11elemf1elemf3f10iter := range f11elemf1iter.InstanceRequirements.CpuManufacturers { + var f11elemf1elemf3f10elem *string + f11elemf1elemf3f10elem = aws.String(string(f11elemf1elemf3f10iter)) + f11elemf1elemf3f10 = append(f11elemf1elemf3f10, f11elemf1elemf3f10elem) + } + f11elemf1elemf3.CPUManufacturers = f11elemf1elemf3f10 + } + if f11elemf1iter.InstanceRequirements.ExcludedInstanceTypes != nil { + f11elemf1elemf3.ExcludedInstanceTypes = aws.StringSlice(f11elemf1iter.InstanceRequirements.ExcludedInstanceTypes) + } + if f11elemf1iter.InstanceRequirements.InstanceGenerations != nil { + f11elemf1elemf3f12 := []*string{} + for _, f11elemf1elemf3f12iter := range f11elemf1iter.InstanceRequirements.InstanceGenerations { + var f11elemf1elemf3f12elem *string + f11elemf1elemf3f12elem = aws.String(string(f11elemf1elemf3f12iter)) + f11elemf1elemf3f12 = append(f11elemf1elemf3f12, f11elemf1elemf3f12elem) + } + f11elemf1elemf3.InstanceGenerations = f11elemf1elemf3f12 + } + if f11elemf1iter.InstanceRequirements.LocalStorage != "" { + f11elemf1elemf3.LocalStorage = aws.String(string(f11elemf1iter.InstanceRequirements.LocalStorage)) + } + if f11elemf1iter.InstanceRequirements.LocalStorageTypes != nil { + f11elemf1elemf3f14 := []*string{} + for _, f11elemf1elemf3f14iter := range f11elemf1iter.InstanceRequirements.LocalStorageTypes { + var f11elemf1elemf3f14elem *string + f11elemf1elemf3f14elem = aws.String(string(f11elemf1elemf3f14iter)) + f11elemf1elemf3f14 = append(f11elemf1elemf3f14, f11elemf1elemf3f14elem) + } + f11elemf1elemf3.LocalStorageTypes = f11elemf1elemf3f14 + } + if f11elemf1iter.InstanceRequirements.MaxSpotPriceAsPercentageOfOptimalOnDemandPrice != nil { + maxSpotPriceAsPercentageOfOptimalOnDemandPriceCopy := int64(*f11elemf1iter.InstanceRequirements.MaxSpotPriceAsPercentageOfOptimalOnDemandPrice) + f11elemf1elemf3.MaxSpotPriceAsPercentageOfOptimalOnDemandPrice = &maxSpotPriceAsPercentageOfOptimalOnDemandPriceCopy + } + if f11elemf1iter.InstanceRequirements.MemoryGiBPerVCpu != nil { + f11elemf1elemf3f16 := &svcapitypes.MemoryGiBPerVCPURequest{} + if f11elemf1iter.InstanceRequirements.MemoryGiBPerVCpu.Max != nil { + f11elemf1elemf3f16.Max = f11elemf1iter.InstanceRequirements.MemoryGiBPerVCpu.Max + } + if f11elemf1iter.InstanceRequirements.MemoryGiBPerVCpu.Min != nil { + f11elemf1elemf3f16.Min = f11elemf1iter.InstanceRequirements.MemoryGiBPerVCpu.Min + } + f11elemf1elemf3.MemoryGiBPerVCPU = f11elemf1elemf3f16 + } + if f11elemf1iter.InstanceRequirements.MemoryMiB != nil { + f11elemf1elemf3f17 := &svcapitypes.MemoryMiBRequest{} + if f11elemf1iter.InstanceRequirements.MemoryMiB.Max != nil { + maxCopy := int64(*f11elemf1iter.InstanceRequirements.MemoryMiB.Max) + f11elemf1elemf3f17.Max = &maxCopy + } + if f11elemf1iter.InstanceRequirements.MemoryMiB.Min != nil { + minCopy := int64(*f11elemf1iter.InstanceRequirements.MemoryMiB.Min) + f11elemf1elemf3f17.Min = &minCopy + } + f11elemf1elemf3.MemoryMiB = f11elemf1elemf3f17 + } + if f11elemf1iter.InstanceRequirements.NetworkBandwidthGbps != nil { + f11elemf1elemf3f18 := &svcapitypes.NetworkBandwidthGbpsRequest{} + if f11elemf1iter.InstanceRequirements.NetworkBandwidthGbps.Max != nil { + f11elemf1elemf3f18.Max = f11elemf1iter.InstanceRequirements.NetworkBandwidthGbps.Max + } + if f11elemf1iter.InstanceRequirements.NetworkBandwidthGbps.Min != nil { + f11elemf1elemf3f18.Min = f11elemf1iter.InstanceRequirements.NetworkBandwidthGbps.Min + } + f11elemf1elemf3.NetworkBandwidthGbps = f11elemf1elemf3f18 + } + if f11elemf1iter.InstanceRequirements.NetworkInterfaceCount != nil { + f11elemf1elemf3f19 := &svcapitypes.NetworkInterfaceCountRequest{} + if f11elemf1iter.InstanceRequirements.NetworkInterfaceCount.Max != nil { + maxCopy := int64(*f11elemf1iter.InstanceRequirements.NetworkInterfaceCount.Max) + f11elemf1elemf3f19.Max = &maxCopy + } + if f11elemf1iter.InstanceRequirements.NetworkInterfaceCount.Min != nil { + minCopy := int64(*f11elemf1iter.InstanceRequirements.NetworkInterfaceCount.Min) + f11elemf1elemf3f19.Min = &minCopy + } + f11elemf1elemf3.NetworkInterfaceCount = f11elemf1elemf3f19 + } + if f11elemf1iter.InstanceRequirements.OnDemandMaxPricePercentageOverLowestPrice != nil { + onDemandMaxPricePercentageOverLowestPriceCopy := int64(*f11elemf1iter.InstanceRequirements.OnDemandMaxPricePercentageOverLowestPrice) + f11elemf1elemf3.OnDemandMaxPricePercentageOverLowestPrice = &onDemandMaxPricePercentageOverLowestPriceCopy + } + if f11elemf1iter.InstanceRequirements.RequireHibernateSupport != nil { + f11elemf1elemf3.RequireHibernateSupport = f11elemf1iter.InstanceRequirements.RequireHibernateSupport + } + if f11elemf1iter.InstanceRequirements.SpotMaxPricePercentageOverLowestPrice != nil { + spotMaxPricePercentageOverLowestPriceCopy := int64(*f11elemf1iter.InstanceRequirements.SpotMaxPricePercentageOverLowestPrice) + f11elemf1elemf3.SpotMaxPricePercentageOverLowestPrice = &spotMaxPricePercentageOverLowestPriceCopy + } + if f11elemf1iter.InstanceRequirements.TotalLocalStorageGB != nil { + f11elemf1elemf3f23 := &svcapitypes.TotalLocalStorageGBRequest{} + if f11elemf1iter.InstanceRequirements.TotalLocalStorageGB.Max != nil { + f11elemf1elemf3f23.Max = f11elemf1iter.InstanceRequirements.TotalLocalStorageGB.Max + } + if f11elemf1iter.InstanceRequirements.TotalLocalStorageGB.Min != nil { + f11elemf1elemf3f23.Min = f11elemf1iter.InstanceRequirements.TotalLocalStorageGB.Min + } + f11elemf1elemf3.TotalLocalStorageGB = f11elemf1elemf3f23 + } + if f11elemf1iter.InstanceRequirements.VCpuCount != nil { + f11elemf1elemf3f24 := &svcapitypes.VCPUCountRangeRequest{} + if f11elemf1iter.InstanceRequirements.VCpuCount.Max != nil { + maxCopy := int64(*f11elemf1iter.InstanceRequirements.VCpuCount.Max) + f11elemf1elemf3f24.Max = &maxCopy + } + if f11elemf1iter.InstanceRequirements.VCpuCount.Min != nil { + minCopy := int64(*f11elemf1iter.InstanceRequirements.VCpuCount.Min) + f11elemf1elemf3f24.Min = &minCopy + } + f11elemf1elemf3.VCPUCount = f11elemf1elemf3f24 + } + f11elemf1elem.InstanceRequirements = f11elemf1elemf3 + } + if f11elemf1iter.InstanceType != "" { + f11elemf1elem.InstanceType = aws.String(string(f11elemf1iter.InstanceType)) + } + if f11elemf1iter.MaxPrice != nil { + f11elemf1elem.MaxPrice = f11elemf1iter.MaxPrice + } + if f11elemf1iter.Placement != nil { + f11elemf1elemf6 := &svcapitypes.Placement{} + if f11elemf1iter.Placement.GroupName != nil { + f11elemf1elemf6.GroupName = f11elemf1iter.Placement.GroupName + } + f11elemf1elem.Placement = f11elemf1elemf6 + } + if f11elemf1iter.Priority != nil { + f11elemf1elem.Priority = f11elemf1iter.Priority + } + if f11elemf1iter.SubnetId != nil { + f11elemf1elem.SubnetID = f11elemf1iter.SubnetId + } + if f11elemf1iter.WeightedCapacity != nil { + f11elemf1elem.WeightedCapacity = f11elemf1iter.WeightedCapacity + } + f11elemf1 = append(f11elemf1, f11elemf1elem) + } + f11elem.Overrides = f11elemf1 + } + f11 = append(f11, f11elem) + } + ko.Spec.LaunchTemplateConfigs = f11 + } else { + ko.Spec.LaunchTemplateConfigs = nil + } + if elem.OnDemandOptions != nil { + f12 := &svcapitypes.OnDemandOptionsRequest{} + if elem.OnDemandOptions.AllocationStrategy != "" { + f12.AllocationStrategy = aws.String(string(elem.OnDemandOptions.AllocationStrategy)) + } + if elem.OnDemandOptions.CapacityReservationOptions != nil { + f12f1 := &svcapitypes.CapacityReservationOptionsRequest{} + if elem.OnDemandOptions.CapacityReservationOptions.UsageStrategy != "" { + f12f1.UsageStrategy = aws.String(string(elem.OnDemandOptions.CapacityReservationOptions.UsageStrategy)) + } + f12.CapacityReservationOptions = f12f1 + } + if elem.OnDemandOptions.MaxTotalPrice != nil { + f12.MaxTotalPrice = elem.OnDemandOptions.MaxTotalPrice + } + if elem.OnDemandOptions.MinTargetCapacity != nil { + minTargetCapacityCopy := int64(*elem.OnDemandOptions.MinTargetCapacity) + f12.MinTargetCapacity = &minTargetCapacityCopy + } + if elem.OnDemandOptions.SingleAvailabilityZone != nil { + f12.SingleAvailabilityZone = elem.OnDemandOptions.SingleAvailabilityZone + } + if elem.OnDemandOptions.SingleInstanceType != nil { + f12.SingleInstanceType = elem.OnDemandOptions.SingleInstanceType + } + ko.Spec.OnDemandOptions = f12 + } else { + ko.Spec.OnDemandOptions = nil + } + if elem.ReplaceUnhealthyInstances != nil { + ko.Spec.ReplaceUnhealthyInstances = elem.ReplaceUnhealthyInstances + } else { + ko.Spec.ReplaceUnhealthyInstances = nil + } + if elem.SpotOptions != nil { + f14 := &svcapitypes.SpotOptionsRequest{} + if elem.SpotOptions.AllocationStrategy != "" { + f14.AllocationStrategy = aws.String(string(elem.SpotOptions.AllocationStrategy)) + } + if elem.SpotOptions.InstanceInterruptionBehavior != "" { + f14.InstanceInterruptionBehavior = aws.String(string(elem.SpotOptions.InstanceInterruptionBehavior)) + } + if elem.SpotOptions.InstancePoolsToUseCount != nil { + instancePoolsToUseCountCopy := int64(*elem.SpotOptions.InstancePoolsToUseCount) + f14.InstancePoolsToUseCount = &instancePoolsToUseCountCopy + } + if elem.SpotOptions.MaintenanceStrategies != nil { + f14f3 := &svcapitypes.FleetSpotMaintenanceStrategiesRequest{} + if elem.SpotOptions.MaintenanceStrategies.CapacityRebalance != nil { + f14f3f0 := &svcapitypes.FleetSpotCapacityRebalanceRequest{} + if elem.SpotOptions.MaintenanceStrategies.CapacityRebalance.ReplacementStrategy != "" { + f14f3f0.ReplacementStrategy = aws.String(string(elem.SpotOptions.MaintenanceStrategies.CapacityRebalance.ReplacementStrategy)) + } + if elem.SpotOptions.MaintenanceStrategies.CapacityRebalance.TerminationDelay != nil { + terminationDelayCopy := int64(*elem.SpotOptions.MaintenanceStrategies.CapacityRebalance.TerminationDelay) + f14f3f0.TerminationDelay = &terminationDelayCopy + } + f14f3.CapacityRebalance = f14f3f0 + } + f14.MaintenanceStrategies = f14f3 + } + if elem.SpotOptions.MaxTotalPrice != nil { + f14.MaxTotalPrice = elem.SpotOptions.MaxTotalPrice + } + if elem.SpotOptions.MinTargetCapacity != nil { + minTargetCapacityCopy := int64(*elem.SpotOptions.MinTargetCapacity) + f14.MinTargetCapacity = &minTargetCapacityCopy + } + if elem.SpotOptions.SingleAvailabilityZone != nil { + f14.SingleAvailabilityZone = elem.SpotOptions.SingleAvailabilityZone + } + if elem.SpotOptions.SingleInstanceType != nil { + f14.SingleInstanceType = elem.SpotOptions.SingleInstanceType + } + ko.Spec.SpotOptions = f14 + } else { + ko.Spec.SpotOptions = nil + } + if elem.Tags != nil { + f15 := []*svcapitypes.Tag{} + for _, f15iter := range elem.Tags { + f15elem := &svcapitypes.Tag{} + if f15iter.Key != nil { + f15elem.Key = f15iter.Key + } + if f15iter.Value != nil { + f15elem.Value = f15iter.Value + } + f15 = append(f15, f15elem) + } + ko.Spec.Tags = f15 + } else { + ko.Spec.Tags = nil + } + if elem.TargetCapacitySpecification != nil { + f16 := &svcapitypes.TargetCapacitySpecificationRequest{} + if elem.TargetCapacitySpecification.DefaultTargetCapacityType != "" { + f16.DefaultTargetCapacityType = aws.String(string(elem.TargetCapacitySpecification.DefaultTargetCapacityType)) + } + if elem.TargetCapacitySpecification.OnDemandTargetCapacity != nil { + onDemandTargetCapacityCopy := int64(*elem.TargetCapacitySpecification.OnDemandTargetCapacity) + f16.OnDemandTargetCapacity = &onDemandTargetCapacityCopy + } + if elem.TargetCapacitySpecification.SpotTargetCapacity != nil { + spotTargetCapacityCopy := int64(*elem.TargetCapacitySpecification.SpotTargetCapacity) + f16.SpotTargetCapacity = &spotTargetCapacityCopy + } + if elem.TargetCapacitySpecification.TargetCapacityUnitType != "" { + f16.TargetCapacityUnitType = aws.String(string(elem.TargetCapacitySpecification.TargetCapacityUnitType)) + } + if elem.TargetCapacitySpecification.TotalTargetCapacity != nil { + totalTargetCapacityCopy := int64(*elem.TargetCapacitySpecification.TotalTargetCapacity) + f16.TotalTargetCapacity = &totalTargetCapacityCopy + } + ko.Spec.TargetCapacitySpecification = f16 + } else { + ko.Spec.TargetCapacitySpecification = nil + } + if elem.TerminateInstancesWithExpiration != nil { + ko.Spec.TerminateInstancesWithExpiration = elem.TerminateInstancesWithExpiration + } else { + ko.Spec.TerminateInstancesWithExpiration = nil + } + if elem.Type != "" { + ko.Spec.Type = aws.String(string(elem.Type)) + } else { + ko.Spec.Type = nil + } + if elem.ValidFrom != nil { + ko.Spec.ValidFrom = &metav1.Time{*elem.ValidFrom} + } else { + ko.Spec.ValidFrom = nil + } + if elem.ValidUntil != nil { + ko.Spec.ValidUntil = &metav1.Time{*elem.ValidUntil} + } else { + ko.Spec.ValidUntil = nil + } + found = true + break + } + if !found { + return nil, ackerr.NotFound + } + + rm.setStatusDefaults(ko) + // Here we want to check if the fleet is deleted + // returning NotFound will trigger a create + if fleetDeleted(r) { + return nil, ackerr.NotFound + } + + toAdd, toDelete := computeTagsDelta(r.ko.Spec.Tags, ko.Spec.Tags) + if len(toAdd) == 0 && len(toDelete) == 0 { + // if resource's initial tags and response tags are equal, + // then assign resource's tags to maintain tag order + ko.Spec.Tags = r.ko.Spec.Tags + } + + return &resource{ko}, nil +} + +// requiredFieldsMissingFromReadManyInput returns true if there are any fields +// for the ReadMany Input shape that are required but not present in the +// resource's Spec or Status +func (rm *resourceManager) requiredFieldsMissingFromReadManyInput( + r *resource, +) bool { + return r.ko.Status.FleetID == nil + +} + +// newListRequestPayload returns SDK-specific struct for the HTTP request +// payload of the List API call for the resource +func (rm *resourceManager) newListRequestPayload( + r *resource, +) (*svcsdk.DescribeFleetsInput, error) { + res := &svcsdk.DescribeFleetsInput{} + + if r.ko.Status.FleetID != nil { + f2 := []string{} + f2 = append(f2, *r.ko.Status.FleetID) + res.FleetIds = f2 + } + + return res, nil +} + +// sdkCreate creates the supplied resource in the backend AWS service API and +// returns a copy of the resource with resource fields (in both Spec and +// Status) filled in with values from the CREATE API operation's Output shape. +func (rm *resourceManager) sdkCreate( + ctx context.Context, + desired *resource, +) (created *resource, err error) { + rlog := ackrtlog.FromContext(ctx) + exit := rlog.Trace("rm.sdkCreate") + defer func() { + exit(err) + }() + input, err := rm.newCreateRequestPayload(ctx, desired) + if err != nil { + return nil, err + } + updateTagSpecificationsInCreateRequest(desired, input) + + for _, config := range input.LaunchTemplateConfigs { + if config.LaunchTemplateSpecification != nil { + + // Ensure Launch Template Version is int and not $Latest/$Default + // Preventing those values as as those strings are updated in the backend with the ints they represent + // This confuses the reconciliation as the aws state falls out of sync with the CRD + // If we stick to int strings, all works smoothly + + _, err := strconv.Atoi(*config.LaunchTemplateSpecification.Version) + if err != nil { + msg := "Only int values are supported for Launch Template Version in EC2 fleet spec" + return nil, ackerr.NewTerminalError(fmt.Errorf("%s", msg)) + } + } + } + + var resp *svcsdk.CreateFleetOutput + _ = resp + resp, err = rm.sdkapi.CreateFleet(ctx, input) + rm.metrics.RecordAPICall("CREATE", "CreateFleet", err) + if err != nil { + return nil, err + } + // Merge in the information we read from the API call above to the copy of + // the original Kubernetes object we passed to the function + ko := desired.ko.DeepCopy() + + if resp.Errors != nil { + f0 := []*svcapitypes.CreateFleetError{} + for _, f0iter := range resp.Errors { + f0elem := &svcapitypes.CreateFleetError{} + if f0iter.ErrorCode != nil { + f0elem.ErrorCode = f0iter.ErrorCode + } + if f0iter.ErrorMessage != nil { + f0elem.ErrorMessage = f0iter.ErrorMessage + } + if f0iter.LaunchTemplateAndOverrides != nil { + f0elemf2 := &svcapitypes.LaunchTemplateAndOverridesResponse{} + if f0iter.LaunchTemplateAndOverrides.LaunchTemplateSpecification != nil { + f0elemf2f0 := &svcapitypes.FleetLaunchTemplateSpecification{} + if f0iter.LaunchTemplateAndOverrides.LaunchTemplateSpecification.LaunchTemplateId != nil { + f0elemf2f0.LaunchTemplateID = f0iter.LaunchTemplateAndOverrides.LaunchTemplateSpecification.LaunchTemplateId + } + if f0iter.LaunchTemplateAndOverrides.LaunchTemplateSpecification.LaunchTemplateName != nil { + f0elemf2f0.LaunchTemplateName = f0iter.LaunchTemplateAndOverrides.LaunchTemplateSpecification.LaunchTemplateName + } + if f0iter.LaunchTemplateAndOverrides.LaunchTemplateSpecification.Version != nil { + f0elemf2f0.Version = f0iter.LaunchTemplateAndOverrides.LaunchTemplateSpecification.Version + } + f0elemf2.LaunchTemplateSpecification = f0elemf2f0 + } + if f0iter.LaunchTemplateAndOverrides.Overrides != nil { + f0elemf2f1 := &svcapitypes.FleetLaunchTemplateOverrides{} + if f0iter.LaunchTemplateAndOverrides.Overrides.AvailabilityZone != nil { + f0elemf2f1.AvailabilityZone = f0iter.LaunchTemplateAndOverrides.Overrides.AvailabilityZone + } + if f0iter.LaunchTemplateAndOverrides.Overrides.BlockDeviceMappings != nil { + f0elemf2f1f1 := []*svcapitypes.BlockDeviceMappingResponse{} + for _, f0elemf2f1f1iter := range f0iter.LaunchTemplateAndOverrides.Overrides.BlockDeviceMappings { + f0elemf2f1f1elem := &svcapitypes.BlockDeviceMappingResponse{} + if f0elemf2f1f1iter.DeviceName != nil { + f0elemf2f1f1elem.DeviceName = f0elemf2f1f1iter.DeviceName + } + if f0elemf2f1f1iter.Ebs != nil { + f0elemf2f1f1elemf1 := &svcapitypes.EBSBlockDeviceResponse{} + if f0elemf2f1f1iter.Ebs.DeleteOnTermination != nil { + f0elemf2f1f1elemf1.DeleteOnTermination = f0elemf2f1f1iter.Ebs.DeleteOnTermination + } + if f0elemf2f1f1iter.Ebs.Encrypted != nil { + f0elemf2f1f1elemf1.Encrypted = f0elemf2f1f1iter.Ebs.Encrypted + } + if f0elemf2f1f1iter.Ebs.Iops != nil { + iopsCopy := int64(*f0elemf2f1f1iter.Ebs.Iops) + f0elemf2f1f1elemf1.IOPS = &iopsCopy + } + if f0elemf2f1f1iter.Ebs.KmsKeyId != nil { + f0elemf2f1f1elemf1.KMSKeyID = f0elemf2f1f1iter.Ebs.KmsKeyId + } + if f0elemf2f1f1iter.Ebs.SnapshotId != nil { + f0elemf2f1f1elemf1.SnapshotID = f0elemf2f1f1iter.Ebs.SnapshotId + } + if f0elemf2f1f1iter.Ebs.Throughput != nil { + throughputCopy := int64(*f0elemf2f1f1iter.Ebs.Throughput) + f0elemf2f1f1elemf1.Throughput = &throughputCopy + } + if f0elemf2f1f1iter.Ebs.VolumeSize != nil { + volumeSizeCopy := int64(*f0elemf2f1f1iter.Ebs.VolumeSize) + f0elemf2f1f1elemf1.VolumeSize = &volumeSizeCopy + } + if f0elemf2f1f1iter.Ebs.VolumeType != "" { + f0elemf2f1f1elemf1.VolumeType = aws.String(string(f0elemf2f1f1iter.Ebs.VolumeType)) + } + f0elemf2f1f1elem.EBS = f0elemf2f1f1elemf1 + } + if f0elemf2f1f1iter.NoDevice != nil { + f0elemf2f1f1elem.NoDevice = f0elemf2f1f1iter.NoDevice + } + if f0elemf2f1f1iter.VirtualName != nil { + f0elemf2f1f1elem.VirtualName = f0elemf2f1f1iter.VirtualName + } + f0elemf2f1f1 = append(f0elemf2f1f1, f0elemf2f1f1elem) + } + f0elemf2f1.BlockDeviceMappings = f0elemf2f1f1 + } + if f0iter.LaunchTemplateAndOverrides.Overrides.ImageId != nil { + f0elemf2f1.ImageID = f0iter.LaunchTemplateAndOverrides.Overrides.ImageId + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements != nil { + f0elemf2f1f3 := &svcapitypes.InstanceRequirements{} + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorCount != nil { + f0elemf2f1f3f0 := &svcapitypes.AcceleratorCount{} + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorCount.Max != nil { + maxCopy := int64(*f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorCount.Max) + f0elemf2f1f3f0.Max = &maxCopy + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorCount.Min != nil { + minCopy := int64(*f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorCount.Min) + f0elemf2f1f3f0.Min = &minCopy + } + f0elemf2f1f3.AcceleratorCount = f0elemf2f1f3f0 + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorManufacturers != nil { + f0elemf2f1f3f1 := []*string{} + for _, f0elemf2f1f3f1iter := range f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorManufacturers { + var f0elemf2f1f3f1elem *string + f0elemf2f1f3f1elem = aws.String(string(f0elemf2f1f3f1iter)) + f0elemf2f1f3f1 = append(f0elemf2f1f3f1, f0elemf2f1f3f1elem) + } + f0elemf2f1f3.AcceleratorManufacturers = f0elemf2f1f3f1 + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorNames != nil { + f0elemf2f1f3f2 := []*string{} + for _, f0elemf2f1f3f2iter := range f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorNames { + var f0elemf2f1f3f2elem *string + f0elemf2f1f3f2elem = aws.String(string(f0elemf2f1f3f2iter)) + f0elemf2f1f3f2 = append(f0elemf2f1f3f2, f0elemf2f1f3f2elem) + } + f0elemf2f1f3.AcceleratorNames = f0elemf2f1f3f2 + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorTotalMemoryMiB != nil { + f0elemf2f1f3f3 := &svcapitypes.AcceleratorTotalMemoryMiB{} + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorTotalMemoryMiB.Max != nil { + maxCopy := int64(*f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorTotalMemoryMiB.Max) + f0elemf2f1f3f3.Max = &maxCopy + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorTotalMemoryMiB.Min != nil { + minCopy := int64(*f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorTotalMemoryMiB.Min) + f0elemf2f1f3f3.Min = &minCopy + } + f0elemf2f1f3.AcceleratorTotalMemoryMiB = f0elemf2f1f3f3 + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorTypes != nil { + f0elemf2f1f3f4 := []*string{} + for _, f0elemf2f1f3f4iter := range f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AcceleratorTypes { + var f0elemf2f1f3f4elem *string + f0elemf2f1f3f4elem = aws.String(string(f0elemf2f1f3f4iter)) + f0elemf2f1f3f4 = append(f0elemf2f1f3f4, f0elemf2f1f3f4elem) + } + f0elemf2f1f3.AcceleratorTypes = f0elemf2f1f3f4 + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AllowedInstanceTypes != nil { + f0elemf2f1f3.AllowedInstanceTypes = aws.StringSlice(f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.AllowedInstanceTypes) + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BareMetal != "" { + f0elemf2f1f3.BareMetal = aws.String(string(f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BareMetal)) + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BaselineEbsBandwidthMbps != nil { + f0elemf2f1f3f7 := &svcapitypes.BaselineEBSBandwidthMbps{} + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BaselineEbsBandwidthMbps.Max != nil { + maxCopy := int64(*f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BaselineEbsBandwidthMbps.Max) + f0elemf2f1f3f7.Max = &maxCopy + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BaselineEbsBandwidthMbps.Min != nil { + minCopy := int64(*f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BaselineEbsBandwidthMbps.Min) + f0elemf2f1f3f7.Min = &minCopy + } + f0elemf2f1f3.BaselineEBSBandwidthMbps = f0elemf2f1f3f7 + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BaselinePerformanceFactors != nil { + f0elemf2f1f3f8 := &svcapitypes.BaselinePerformanceFactors{} + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BaselinePerformanceFactors.Cpu != nil { + f0elemf2f1f3f8f0 := &svcapitypes.CPUPerformanceFactor{} + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BaselinePerformanceFactors.Cpu.References != nil { + f0elemf2f1f3f8f0f0 := []*svcapitypes.PerformanceFactorReference{} + for _, f0elemf2f1f3f8f0f0iter := range f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BaselinePerformanceFactors.Cpu.References { + f0elemf2f1f3f8f0f0elem := &svcapitypes.PerformanceFactorReference{} + if f0elemf2f1f3f8f0f0iter.InstanceFamily != nil { + f0elemf2f1f3f8f0f0elem.InstanceFamily = f0elemf2f1f3f8f0f0iter.InstanceFamily + } + f0elemf2f1f3f8f0f0 = append(f0elemf2f1f3f8f0f0, f0elemf2f1f3f8f0f0elem) + } + f0elemf2f1f3f8f0.References = f0elemf2f1f3f8f0f0 + } + f0elemf2f1f3f8.CPU = f0elemf2f1f3f8f0 + } + f0elemf2f1f3.BaselinePerformanceFactors = f0elemf2f1f3f8 + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BurstablePerformance != "" { + f0elemf2f1f3.BurstablePerformance = aws.String(string(f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.BurstablePerformance)) + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.CpuManufacturers != nil { + f0elemf2f1f3f10 := []*string{} + for _, f0elemf2f1f3f10iter := range f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.CpuManufacturers { + var f0elemf2f1f3f10elem *string + f0elemf2f1f3f10elem = aws.String(string(f0elemf2f1f3f10iter)) + f0elemf2f1f3f10 = append(f0elemf2f1f3f10, f0elemf2f1f3f10elem) + } + f0elemf2f1f3.CPUManufacturers = f0elemf2f1f3f10 + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.ExcludedInstanceTypes != nil { + f0elemf2f1f3.ExcludedInstanceTypes = aws.StringSlice(f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.ExcludedInstanceTypes) + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.InstanceGenerations != nil { + f0elemf2f1f3f12 := []*string{} + for _, f0elemf2f1f3f12iter := range f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.InstanceGenerations { + var f0elemf2f1f3f12elem *string + f0elemf2f1f3f12elem = aws.String(string(f0elemf2f1f3f12iter)) + f0elemf2f1f3f12 = append(f0elemf2f1f3f12, f0elemf2f1f3f12elem) + } + f0elemf2f1f3.InstanceGenerations = f0elemf2f1f3f12 + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.LocalStorage != "" { + f0elemf2f1f3.LocalStorage = aws.String(string(f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.LocalStorage)) + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.LocalStorageTypes != nil { + f0elemf2f1f3f14 := []*string{} + for _, f0elemf2f1f3f14iter := range f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.LocalStorageTypes { + var f0elemf2f1f3f14elem *string + f0elemf2f1f3f14elem = aws.String(string(f0elemf2f1f3f14iter)) + f0elemf2f1f3f14 = append(f0elemf2f1f3f14, f0elemf2f1f3f14elem) + } + f0elemf2f1f3.LocalStorageTypes = f0elemf2f1f3f14 + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MaxSpotPriceAsPercentageOfOptimalOnDemandPrice != nil { + maxSpotPriceAsPercentageOfOptimalOnDemandPriceCopy := int64(*f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MaxSpotPriceAsPercentageOfOptimalOnDemandPrice) + f0elemf2f1f3.MaxSpotPriceAsPercentageOfOptimalOnDemandPrice = &maxSpotPriceAsPercentageOfOptimalOnDemandPriceCopy + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryGiBPerVCpu != nil { + f0elemf2f1f3f16 := &svcapitypes.MemoryGiBPerVCPU{} + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryGiBPerVCpu.Max != nil { + f0elemf2f1f3f16.Max = f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryGiBPerVCpu.Max + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryGiBPerVCpu.Min != nil { + f0elemf2f1f3f16.Min = f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryGiBPerVCpu.Min + } + f0elemf2f1f3.MemoryGiBPerVCPU = f0elemf2f1f3f16 + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryMiB != nil { + f0elemf2f1f3f17 := &svcapitypes.MemoryMiB{} + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryMiB.Max != nil { + maxCopy := int64(*f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryMiB.Max) + f0elemf2f1f3f17.Max = &maxCopy + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryMiB.Min != nil { + minCopy := int64(*f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.MemoryMiB.Min) + f0elemf2f1f3f17.Min = &minCopy + } + f0elemf2f1f3.MemoryMiB = f0elemf2f1f3f17 + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkBandwidthGbps != nil { + f0elemf2f1f3f18 := &svcapitypes.NetworkBandwidthGbps{} + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkBandwidthGbps.Max != nil { + f0elemf2f1f3f18.Max = f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkBandwidthGbps.Max + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkBandwidthGbps.Min != nil { + f0elemf2f1f3f18.Min = f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkBandwidthGbps.Min + } + f0elemf2f1f3.NetworkBandwidthGbps = f0elemf2f1f3f18 + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkInterfaceCount != nil { + f0elemf2f1f3f19 := &svcapitypes.NetworkInterfaceCount{} + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkInterfaceCount.Max != nil { + maxCopy := int64(*f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkInterfaceCount.Max) + f0elemf2f1f3f19.Max = &maxCopy + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkInterfaceCount.Min != nil { + minCopy := int64(*f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.NetworkInterfaceCount.Min) + f0elemf2f1f3f19.Min = &minCopy + } + f0elemf2f1f3.NetworkInterfaceCount = f0elemf2f1f3f19 + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.OnDemandMaxPricePercentageOverLowestPrice != nil { + onDemandMaxPricePercentageOverLowestPriceCopy := int64(*f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.OnDemandMaxPricePercentageOverLowestPrice) + f0elemf2f1f3.OnDemandMaxPricePercentageOverLowestPrice = &onDemandMaxPricePercentageOverLowestPriceCopy + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.RequireHibernateSupport != nil { + f0elemf2f1f3.RequireHibernateSupport = f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.RequireHibernateSupport + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.SpotMaxPricePercentageOverLowestPrice != nil { + spotMaxPricePercentageOverLowestPriceCopy := int64(*f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.SpotMaxPricePercentageOverLowestPrice) + f0elemf2f1f3.SpotMaxPricePercentageOverLowestPrice = &spotMaxPricePercentageOverLowestPriceCopy + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.TotalLocalStorageGB != nil { + f0elemf2f1f3f23 := &svcapitypes.TotalLocalStorageGB{} + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.TotalLocalStorageGB.Max != nil { + f0elemf2f1f3f23.Max = f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.TotalLocalStorageGB.Max + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.TotalLocalStorageGB.Min != nil { + f0elemf2f1f3f23.Min = f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.TotalLocalStorageGB.Min + } + f0elemf2f1f3.TotalLocalStorageGB = f0elemf2f1f3f23 + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.VCpuCount != nil { + f0elemf2f1f3f24 := &svcapitypes.VCPUCountRange{} + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.VCpuCount.Max != nil { + maxCopy := int64(*f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.VCpuCount.Max) + f0elemf2f1f3f24.Max = &maxCopy + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.VCpuCount.Min != nil { + minCopy := int64(*f0iter.LaunchTemplateAndOverrides.Overrides.InstanceRequirements.VCpuCount.Min) + f0elemf2f1f3f24.Min = &minCopy + } + f0elemf2f1f3.VCPUCount = f0elemf2f1f3f24 + } + f0elemf2f1.InstanceRequirements = f0elemf2f1f3 + } + if f0iter.LaunchTemplateAndOverrides.Overrides.InstanceType != "" { + f0elemf2f1.InstanceType = aws.String(string(f0iter.LaunchTemplateAndOverrides.Overrides.InstanceType)) + } + if f0iter.LaunchTemplateAndOverrides.Overrides.MaxPrice != nil { + f0elemf2f1.MaxPrice = f0iter.LaunchTemplateAndOverrides.Overrides.MaxPrice + } + if f0iter.LaunchTemplateAndOverrides.Overrides.Placement != nil { + f0elemf2f1f6 := &svcapitypes.PlacementResponse{} + if f0iter.LaunchTemplateAndOverrides.Overrides.Placement.GroupName != nil { + f0elemf2f1f6.GroupName = f0iter.LaunchTemplateAndOverrides.Overrides.Placement.GroupName + } + f0elemf2f1.Placement = f0elemf2f1f6 + } + if f0iter.LaunchTemplateAndOverrides.Overrides.Priority != nil { + f0elemf2f1.Priority = f0iter.LaunchTemplateAndOverrides.Overrides.Priority + } + if f0iter.LaunchTemplateAndOverrides.Overrides.SubnetId != nil { + f0elemf2f1.SubnetID = f0iter.LaunchTemplateAndOverrides.Overrides.SubnetId + } + if f0iter.LaunchTemplateAndOverrides.Overrides.WeightedCapacity != nil { + f0elemf2f1.WeightedCapacity = f0iter.LaunchTemplateAndOverrides.Overrides.WeightedCapacity + } + f0elemf2.Overrides = f0elemf2f1 + } + f0elem.LaunchTemplateAndOverrides = f0elemf2 + } + if f0iter.Lifecycle != "" { + f0elem.Lifecycle = aws.String(string(f0iter.Lifecycle)) + } + f0 = append(f0, f0elem) + } + ko.Status.Errors = f0 + } else { + ko.Status.Errors = nil + } + if resp.FleetId != nil { + ko.Status.FleetID = resp.FleetId + } else { + ko.Status.FleetID = nil + } + + rm.setStatusDefaults(ko) + return &resource{ko}, nil +} + +// newCreateRequestPayload returns an SDK-specific struct for the HTTP request +// payload of the Create API call for the resource +func (rm *resourceManager) newCreateRequestPayload( + ctx context.Context, + r *resource, +) (*svcsdk.CreateFleetInput, error) { + res := &svcsdk.CreateFleetInput{} + + if r.ko.Spec.Context != nil { + res.Context = r.ko.Spec.Context + } + if r.ko.Spec.ExcessCapacityTerminationPolicy != nil { + res.ExcessCapacityTerminationPolicy = svcsdktypes.FleetExcessCapacityTerminationPolicy(*r.ko.Spec.ExcessCapacityTerminationPolicy) + } + if r.ko.Spec.LaunchTemplateConfigs != nil { + f2 := []svcsdktypes.FleetLaunchTemplateConfigRequest{} + for _, f2iter := range r.ko.Spec.LaunchTemplateConfigs { + f2elem := &svcsdktypes.FleetLaunchTemplateConfigRequest{} + if f2iter.LaunchTemplateSpecification != nil { + f2elemf0 := &svcsdktypes.FleetLaunchTemplateSpecificationRequest{} + if f2iter.LaunchTemplateSpecification.LaunchTemplateID != nil { + f2elemf0.LaunchTemplateId = f2iter.LaunchTemplateSpecification.LaunchTemplateID + } + if f2iter.LaunchTemplateSpecification.LaunchTemplateName != nil { + f2elemf0.LaunchTemplateName = f2iter.LaunchTemplateSpecification.LaunchTemplateName + } + if f2iter.LaunchTemplateSpecification.Version != nil { + f2elemf0.Version = f2iter.LaunchTemplateSpecification.Version + } + f2elem.LaunchTemplateSpecification = f2elemf0 + } + if f2iter.Overrides != nil { + f2elemf1 := []svcsdktypes.FleetLaunchTemplateOverridesRequest{} + for _, f2elemf1iter := range f2iter.Overrides { + f2elemf1elem := &svcsdktypes.FleetLaunchTemplateOverridesRequest{} + if f2elemf1iter.AvailabilityZone != nil { + f2elemf1elem.AvailabilityZone = f2elemf1iter.AvailabilityZone + } + if f2elemf1iter.BlockDeviceMappings != nil { + f2elemf1elemf1 := []svcsdktypes.FleetBlockDeviceMappingRequest{} + for _, f2elemf1elemf1iter := range f2elemf1iter.BlockDeviceMappings { + f2elemf1elemf1elem := &svcsdktypes.FleetBlockDeviceMappingRequest{} + if f2elemf1elemf1iter.DeviceName != nil { + f2elemf1elemf1elem.DeviceName = f2elemf1elemf1iter.DeviceName + } + if f2elemf1elemf1iter.EBS != nil { + f2elemf1elemf1elemf1 := &svcsdktypes.FleetEbsBlockDeviceRequest{} + if f2elemf1elemf1iter.EBS.DeleteOnTermination != nil { + f2elemf1elemf1elemf1.DeleteOnTermination = f2elemf1elemf1iter.EBS.DeleteOnTermination + } + if f2elemf1elemf1iter.EBS.Encrypted != nil { + f2elemf1elemf1elemf1.Encrypted = f2elemf1elemf1iter.EBS.Encrypted + } + if f2elemf1elemf1iter.EBS.IOPS != nil { + iopsCopy0 := *f2elemf1elemf1iter.EBS.IOPS + if iopsCopy0 > math.MaxInt32 || iopsCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Iops is of type int32") + } + iopsCopy := int32(iopsCopy0) + f2elemf1elemf1elemf1.Iops = &iopsCopy + } + if f2elemf1elemf1iter.EBS.KMSKeyID != nil { + f2elemf1elemf1elemf1.KmsKeyId = f2elemf1elemf1iter.EBS.KMSKeyID + } + if f2elemf1elemf1iter.EBS.SnapshotID != nil { + f2elemf1elemf1elemf1.SnapshotId = f2elemf1elemf1iter.EBS.SnapshotID + } + if f2elemf1elemf1iter.EBS.Throughput != nil { + throughputCopy0 := *f2elemf1elemf1iter.EBS.Throughput + if throughputCopy0 > math.MaxInt32 || throughputCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Throughput is of type int32") + } + throughputCopy := int32(throughputCopy0) + f2elemf1elemf1elemf1.Throughput = &throughputCopy + } + if f2elemf1elemf1iter.EBS.VolumeSize != nil { + volumeSizeCopy0 := *f2elemf1elemf1iter.EBS.VolumeSize + if volumeSizeCopy0 > math.MaxInt32 || volumeSizeCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field VolumeSize is of type int32") + } + volumeSizeCopy := int32(volumeSizeCopy0) + f2elemf1elemf1elemf1.VolumeSize = &volumeSizeCopy + } + if f2elemf1elemf1iter.EBS.VolumeType != nil { + f2elemf1elemf1elemf1.VolumeType = svcsdktypes.VolumeType(*f2elemf1elemf1iter.EBS.VolumeType) + } + f2elemf1elemf1elem.Ebs = f2elemf1elemf1elemf1 + } + if f2elemf1elemf1iter.NoDevice != nil { + f2elemf1elemf1elem.NoDevice = f2elemf1elemf1iter.NoDevice + } + if f2elemf1elemf1iter.VirtualName != nil { + f2elemf1elemf1elem.VirtualName = f2elemf1elemf1iter.VirtualName + } + f2elemf1elemf1 = append(f2elemf1elemf1, *f2elemf1elemf1elem) + } + f2elemf1elem.BlockDeviceMappings = f2elemf1elemf1 + } + if f2elemf1iter.ImageID != nil { + f2elemf1elem.ImageId = f2elemf1iter.ImageID + } + if f2elemf1iter.InstanceRequirements != nil { + f2elemf1elemf3 := &svcsdktypes.InstanceRequirementsRequest{} + if f2elemf1iter.InstanceRequirements.AcceleratorCount != nil { + f2elemf1elemf3f0 := &svcsdktypes.AcceleratorCountRequest{} + if f2elemf1iter.InstanceRequirements.AcceleratorCount.Max != nil { + maxCopy0 := *f2elemf1iter.InstanceRequirements.AcceleratorCount.Max + if maxCopy0 > math.MaxInt32 || maxCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Max is of type int32") + } + maxCopy := int32(maxCopy0) + f2elemf1elemf3f0.Max = &maxCopy + } + if f2elemf1iter.InstanceRequirements.AcceleratorCount.Min != nil { + minCopy0 := *f2elemf1iter.InstanceRequirements.AcceleratorCount.Min + if minCopy0 > math.MaxInt32 || minCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Min is of type int32") + } + minCopy := int32(minCopy0) + f2elemf1elemf3f0.Min = &minCopy + } + f2elemf1elemf3.AcceleratorCount = f2elemf1elemf3f0 + } + if f2elemf1iter.InstanceRequirements.AcceleratorManufacturers != nil { + f2elemf1elemf3f1 := []svcsdktypes.AcceleratorManufacturer{} + for _, f2elemf1elemf3f1iter := range f2elemf1iter.InstanceRequirements.AcceleratorManufacturers { + var f2elemf1elemf3f1elem string + f2elemf1elemf3f1elem = string(*f2elemf1elemf3f1iter) + f2elemf1elemf3f1 = append(f2elemf1elemf3f1, svcsdktypes.AcceleratorManufacturer(f2elemf1elemf3f1elem)) + } + f2elemf1elemf3.AcceleratorManufacturers = f2elemf1elemf3f1 + } + if f2elemf1iter.InstanceRequirements.AcceleratorNames != nil { + f2elemf1elemf3f2 := []svcsdktypes.AcceleratorName{} + for _, f2elemf1elemf3f2iter := range f2elemf1iter.InstanceRequirements.AcceleratorNames { + var f2elemf1elemf3f2elem string + f2elemf1elemf3f2elem = string(*f2elemf1elemf3f2iter) + f2elemf1elemf3f2 = append(f2elemf1elemf3f2, svcsdktypes.AcceleratorName(f2elemf1elemf3f2elem)) + } + f2elemf1elemf3.AcceleratorNames = f2elemf1elemf3f2 + } + if f2elemf1iter.InstanceRequirements.AcceleratorTotalMemoryMiB != nil { + f2elemf1elemf3f3 := &svcsdktypes.AcceleratorTotalMemoryMiBRequest{} + if f2elemf1iter.InstanceRequirements.AcceleratorTotalMemoryMiB.Max != nil { + maxCopy0 := *f2elemf1iter.InstanceRequirements.AcceleratorTotalMemoryMiB.Max + if maxCopy0 > math.MaxInt32 || maxCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Max is of type int32") + } + maxCopy := int32(maxCopy0) + f2elemf1elemf3f3.Max = &maxCopy + } + if f2elemf1iter.InstanceRequirements.AcceleratorTotalMemoryMiB.Min != nil { + minCopy0 := *f2elemf1iter.InstanceRequirements.AcceleratorTotalMemoryMiB.Min + if minCopy0 > math.MaxInt32 || minCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Min is of type int32") + } + minCopy := int32(minCopy0) + f2elemf1elemf3f3.Min = &minCopy + } + f2elemf1elemf3.AcceleratorTotalMemoryMiB = f2elemf1elemf3f3 + } + if f2elemf1iter.InstanceRequirements.AcceleratorTypes != nil { + f2elemf1elemf3f4 := []svcsdktypes.AcceleratorType{} + for _, f2elemf1elemf3f4iter := range f2elemf1iter.InstanceRequirements.AcceleratorTypes { + var f2elemf1elemf3f4elem string + f2elemf1elemf3f4elem = string(*f2elemf1elemf3f4iter) + f2elemf1elemf3f4 = append(f2elemf1elemf3f4, svcsdktypes.AcceleratorType(f2elemf1elemf3f4elem)) + } + f2elemf1elemf3.AcceleratorTypes = f2elemf1elemf3f4 + } + if f2elemf1iter.InstanceRequirements.AllowedInstanceTypes != nil { + f2elemf1elemf3.AllowedInstanceTypes = aws.ToStringSlice(f2elemf1iter.InstanceRequirements.AllowedInstanceTypes) + } + if f2elemf1iter.InstanceRequirements.BareMetal != nil { + f2elemf1elemf3.BareMetal = svcsdktypes.BareMetal(*f2elemf1iter.InstanceRequirements.BareMetal) + } + if f2elemf1iter.InstanceRequirements.BaselineEBSBandwidthMbps != nil { + f2elemf1elemf3f7 := &svcsdktypes.BaselineEbsBandwidthMbpsRequest{} + if f2elemf1iter.InstanceRequirements.BaselineEBSBandwidthMbps.Max != nil { + maxCopy0 := *f2elemf1iter.InstanceRequirements.BaselineEBSBandwidthMbps.Max + if maxCopy0 > math.MaxInt32 || maxCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Max is of type int32") + } + maxCopy := int32(maxCopy0) + f2elemf1elemf3f7.Max = &maxCopy + } + if f2elemf1iter.InstanceRequirements.BaselineEBSBandwidthMbps.Min != nil { + minCopy0 := *f2elemf1iter.InstanceRequirements.BaselineEBSBandwidthMbps.Min + if minCopy0 > math.MaxInt32 || minCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Min is of type int32") + } + minCopy := int32(minCopy0) + f2elemf1elemf3f7.Min = &minCopy + } + f2elemf1elemf3.BaselineEbsBandwidthMbps = f2elemf1elemf3f7 + } + if f2elemf1iter.InstanceRequirements.BaselinePerformanceFactors != nil { + f2elemf1elemf3f8 := &svcsdktypes.BaselinePerformanceFactorsRequest{} + if f2elemf1iter.InstanceRequirements.BaselinePerformanceFactors.CPU != nil { + f2elemf1elemf3f8f0 := &svcsdktypes.CpuPerformanceFactorRequest{} + if f2elemf1iter.InstanceRequirements.BaselinePerformanceFactors.CPU.References != nil { + f2elemf1elemf3f8f0f0 := []svcsdktypes.PerformanceFactorReferenceRequest{} + for _, f2elemf1elemf3f8f0f0iter := range f2elemf1iter.InstanceRequirements.BaselinePerformanceFactors.CPU.References { + f2elemf1elemf3f8f0f0elem := &svcsdktypes.PerformanceFactorReferenceRequest{} + if f2elemf1elemf3f8f0f0iter.InstanceFamily != nil { + f2elemf1elemf3f8f0f0elem.InstanceFamily = f2elemf1elemf3f8f0f0iter.InstanceFamily + } + f2elemf1elemf3f8f0f0 = append(f2elemf1elemf3f8f0f0, *f2elemf1elemf3f8f0f0elem) + } + f2elemf1elemf3f8f0.References = f2elemf1elemf3f8f0f0 + } + f2elemf1elemf3f8.Cpu = f2elemf1elemf3f8f0 + } + f2elemf1elemf3.BaselinePerformanceFactors = f2elemf1elemf3f8 + } + if f2elemf1iter.InstanceRequirements.BurstablePerformance != nil { + f2elemf1elemf3.BurstablePerformance = svcsdktypes.BurstablePerformance(*f2elemf1iter.InstanceRequirements.BurstablePerformance) + } + if f2elemf1iter.InstanceRequirements.CPUManufacturers != nil { + f2elemf1elemf3f10 := []svcsdktypes.CpuManufacturer{} + for _, f2elemf1elemf3f10iter := range f2elemf1iter.InstanceRequirements.CPUManufacturers { + var f2elemf1elemf3f10elem string + f2elemf1elemf3f10elem = string(*f2elemf1elemf3f10iter) + f2elemf1elemf3f10 = append(f2elemf1elemf3f10, svcsdktypes.CpuManufacturer(f2elemf1elemf3f10elem)) + } + f2elemf1elemf3.CpuManufacturers = f2elemf1elemf3f10 + } + if f2elemf1iter.InstanceRequirements.ExcludedInstanceTypes != nil { + f2elemf1elemf3.ExcludedInstanceTypes = aws.ToStringSlice(f2elemf1iter.InstanceRequirements.ExcludedInstanceTypes) + } + if f2elemf1iter.InstanceRequirements.InstanceGenerations != nil { + f2elemf1elemf3f12 := []svcsdktypes.InstanceGeneration{} + for _, f2elemf1elemf3f12iter := range f2elemf1iter.InstanceRequirements.InstanceGenerations { + var f2elemf1elemf3f12elem string + f2elemf1elemf3f12elem = string(*f2elemf1elemf3f12iter) + f2elemf1elemf3f12 = append(f2elemf1elemf3f12, svcsdktypes.InstanceGeneration(f2elemf1elemf3f12elem)) + } + f2elemf1elemf3.InstanceGenerations = f2elemf1elemf3f12 + } + if f2elemf1iter.InstanceRequirements.LocalStorage != nil { + f2elemf1elemf3.LocalStorage = svcsdktypes.LocalStorage(*f2elemf1iter.InstanceRequirements.LocalStorage) + } + if f2elemf1iter.InstanceRequirements.LocalStorageTypes != nil { + f2elemf1elemf3f14 := []svcsdktypes.LocalStorageType{} + for _, f2elemf1elemf3f14iter := range f2elemf1iter.InstanceRequirements.LocalStorageTypes { + var f2elemf1elemf3f14elem string + f2elemf1elemf3f14elem = string(*f2elemf1elemf3f14iter) + f2elemf1elemf3f14 = append(f2elemf1elemf3f14, svcsdktypes.LocalStorageType(f2elemf1elemf3f14elem)) + } + f2elemf1elemf3.LocalStorageTypes = f2elemf1elemf3f14 + } + if f2elemf1iter.InstanceRequirements.MaxSpotPriceAsPercentageOfOptimalOnDemandPrice != nil { + maxSpotPriceAsPercentageOfOptimalOnDemandPriceCopy0 := *f2elemf1iter.InstanceRequirements.MaxSpotPriceAsPercentageOfOptimalOnDemandPrice + if maxSpotPriceAsPercentageOfOptimalOnDemandPriceCopy0 > math.MaxInt32 || maxSpotPriceAsPercentageOfOptimalOnDemandPriceCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field MaxSpotPriceAsPercentageOfOptimalOnDemandPrice is of type int32") + } + maxSpotPriceAsPercentageOfOptimalOnDemandPriceCopy := int32(maxSpotPriceAsPercentageOfOptimalOnDemandPriceCopy0) + f2elemf1elemf3.MaxSpotPriceAsPercentageOfOptimalOnDemandPrice = &maxSpotPriceAsPercentageOfOptimalOnDemandPriceCopy + } + if f2elemf1iter.InstanceRequirements.MemoryGiBPerVCPU != nil { + f2elemf1elemf3f16 := &svcsdktypes.MemoryGiBPerVCpuRequest{} + if f2elemf1iter.InstanceRequirements.MemoryGiBPerVCPU.Max != nil { + f2elemf1elemf3f16.Max = f2elemf1iter.InstanceRequirements.MemoryGiBPerVCPU.Max + } + if f2elemf1iter.InstanceRequirements.MemoryGiBPerVCPU.Min != nil { + f2elemf1elemf3f16.Min = f2elemf1iter.InstanceRequirements.MemoryGiBPerVCPU.Min + } + f2elemf1elemf3.MemoryGiBPerVCpu = f2elemf1elemf3f16 + } + if f2elemf1iter.InstanceRequirements.MemoryMiB != nil { + f2elemf1elemf3f17 := &svcsdktypes.MemoryMiBRequest{} + if f2elemf1iter.InstanceRequirements.MemoryMiB.Max != nil { + maxCopy0 := *f2elemf1iter.InstanceRequirements.MemoryMiB.Max + if maxCopy0 > math.MaxInt32 || maxCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Max is of type int32") + } + maxCopy := int32(maxCopy0) + f2elemf1elemf3f17.Max = &maxCopy + } + if f2elemf1iter.InstanceRequirements.MemoryMiB.Min != nil { + minCopy0 := *f2elemf1iter.InstanceRequirements.MemoryMiB.Min + if minCopy0 > math.MaxInt32 || minCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Min is of type int32") + } + minCopy := int32(minCopy0) + f2elemf1elemf3f17.Min = &minCopy + } + f2elemf1elemf3.MemoryMiB = f2elemf1elemf3f17 + } + if f2elemf1iter.InstanceRequirements.NetworkBandwidthGbps != nil { + f2elemf1elemf3f18 := &svcsdktypes.NetworkBandwidthGbpsRequest{} + if f2elemf1iter.InstanceRequirements.NetworkBandwidthGbps.Max != nil { + f2elemf1elemf3f18.Max = f2elemf1iter.InstanceRequirements.NetworkBandwidthGbps.Max + } + if f2elemf1iter.InstanceRequirements.NetworkBandwidthGbps.Min != nil { + f2elemf1elemf3f18.Min = f2elemf1iter.InstanceRequirements.NetworkBandwidthGbps.Min + } + f2elemf1elemf3.NetworkBandwidthGbps = f2elemf1elemf3f18 + } + if f2elemf1iter.InstanceRequirements.NetworkInterfaceCount != nil { + f2elemf1elemf3f19 := &svcsdktypes.NetworkInterfaceCountRequest{} + if f2elemf1iter.InstanceRequirements.NetworkInterfaceCount.Max != nil { + maxCopy0 := *f2elemf1iter.InstanceRequirements.NetworkInterfaceCount.Max + if maxCopy0 > math.MaxInt32 || maxCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Max is of type int32") + } + maxCopy := int32(maxCopy0) + f2elemf1elemf3f19.Max = &maxCopy + } + if f2elemf1iter.InstanceRequirements.NetworkInterfaceCount.Min != nil { + minCopy0 := *f2elemf1iter.InstanceRequirements.NetworkInterfaceCount.Min + if minCopy0 > math.MaxInt32 || minCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Min is of type int32") + } + minCopy := int32(minCopy0) + f2elemf1elemf3f19.Min = &minCopy + } + f2elemf1elemf3.NetworkInterfaceCount = f2elemf1elemf3f19 + } + if f2elemf1iter.InstanceRequirements.OnDemandMaxPricePercentageOverLowestPrice != nil { + onDemandMaxPricePercentageOverLowestPriceCopy0 := *f2elemf1iter.InstanceRequirements.OnDemandMaxPricePercentageOverLowestPrice + if onDemandMaxPricePercentageOverLowestPriceCopy0 > math.MaxInt32 || onDemandMaxPricePercentageOverLowestPriceCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field OnDemandMaxPricePercentageOverLowestPrice is of type int32") + } + onDemandMaxPricePercentageOverLowestPriceCopy := int32(onDemandMaxPricePercentageOverLowestPriceCopy0) + f2elemf1elemf3.OnDemandMaxPricePercentageOverLowestPrice = &onDemandMaxPricePercentageOverLowestPriceCopy + } + if f2elemf1iter.InstanceRequirements.RequireHibernateSupport != nil { + f2elemf1elemf3.RequireHibernateSupport = f2elemf1iter.InstanceRequirements.RequireHibernateSupport + } + if f2elemf1iter.InstanceRequirements.SpotMaxPricePercentageOverLowestPrice != nil { + spotMaxPricePercentageOverLowestPriceCopy0 := *f2elemf1iter.InstanceRequirements.SpotMaxPricePercentageOverLowestPrice + if spotMaxPricePercentageOverLowestPriceCopy0 > math.MaxInt32 || spotMaxPricePercentageOverLowestPriceCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field SpotMaxPricePercentageOverLowestPrice is of type int32") + } + spotMaxPricePercentageOverLowestPriceCopy := int32(spotMaxPricePercentageOverLowestPriceCopy0) + f2elemf1elemf3.SpotMaxPricePercentageOverLowestPrice = &spotMaxPricePercentageOverLowestPriceCopy + } + if f2elemf1iter.InstanceRequirements.TotalLocalStorageGB != nil { + f2elemf1elemf3f23 := &svcsdktypes.TotalLocalStorageGBRequest{} + if f2elemf1iter.InstanceRequirements.TotalLocalStorageGB.Max != nil { + f2elemf1elemf3f23.Max = f2elemf1iter.InstanceRequirements.TotalLocalStorageGB.Max + } + if f2elemf1iter.InstanceRequirements.TotalLocalStorageGB.Min != nil { + f2elemf1elemf3f23.Min = f2elemf1iter.InstanceRequirements.TotalLocalStorageGB.Min + } + f2elemf1elemf3.TotalLocalStorageGB = f2elemf1elemf3f23 + } + if f2elemf1iter.InstanceRequirements.VCPUCount != nil { + f2elemf1elemf3f24 := &svcsdktypes.VCpuCountRangeRequest{} + if f2elemf1iter.InstanceRequirements.VCPUCount.Max != nil { + maxCopy0 := *f2elemf1iter.InstanceRequirements.VCPUCount.Max + if maxCopy0 > math.MaxInt32 || maxCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Max is of type int32") + } + maxCopy := int32(maxCopy0) + f2elemf1elemf3f24.Max = &maxCopy + } + if f2elemf1iter.InstanceRequirements.VCPUCount.Min != nil { + minCopy0 := *f2elemf1iter.InstanceRequirements.VCPUCount.Min + if minCopy0 > math.MaxInt32 || minCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Min is of type int32") + } + minCopy := int32(minCopy0) + f2elemf1elemf3f24.Min = &minCopy + } + f2elemf1elemf3.VCpuCount = f2elemf1elemf3f24 + } + f2elemf1elem.InstanceRequirements = f2elemf1elemf3 + } + if f2elemf1iter.InstanceType != nil { + f2elemf1elem.InstanceType = svcsdktypes.InstanceType(*f2elemf1iter.InstanceType) + } + if f2elemf1iter.MaxPrice != nil { + f2elemf1elem.MaxPrice = f2elemf1iter.MaxPrice + } + if f2elemf1iter.Placement != nil { + f2elemf1elemf6 := &svcsdktypes.Placement{} + if f2elemf1iter.Placement.Affinity != nil { + f2elemf1elemf6.Affinity = f2elemf1iter.Placement.Affinity + } + if f2elemf1iter.Placement.AvailabilityZone != nil { + f2elemf1elemf6.AvailabilityZone = f2elemf1iter.Placement.AvailabilityZone + } + if f2elemf1iter.Placement.GroupName != nil { + f2elemf1elemf6.GroupName = f2elemf1iter.Placement.GroupName + } + if f2elemf1iter.Placement.HostID != nil { + f2elemf1elemf6.HostId = f2elemf1iter.Placement.HostID + } + if f2elemf1iter.Placement.HostResourceGroupARN != nil { + f2elemf1elemf6.HostResourceGroupArn = f2elemf1iter.Placement.HostResourceGroupARN + } + if f2elemf1iter.Placement.PartitionNumber != nil { + partitionNumberCopy0 := *f2elemf1iter.Placement.PartitionNumber + if partitionNumberCopy0 > math.MaxInt32 || partitionNumberCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field PartitionNumber is of type int32") + } + partitionNumberCopy := int32(partitionNumberCopy0) + f2elemf1elemf6.PartitionNumber = &partitionNumberCopy + } + if f2elemf1iter.Placement.SpreadDomain != nil { + f2elemf1elemf6.SpreadDomain = f2elemf1iter.Placement.SpreadDomain + } + if f2elemf1iter.Placement.Tenancy != nil { + f2elemf1elemf6.Tenancy = svcsdktypes.Tenancy(*f2elemf1iter.Placement.Tenancy) + } + f2elemf1elem.Placement = f2elemf1elemf6 + } + if f2elemf1iter.Priority != nil { + f2elemf1elem.Priority = f2elemf1iter.Priority + } + if f2elemf1iter.SubnetID != nil { + f2elemf1elem.SubnetId = f2elemf1iter.SubnetID + } + if f2elemf1iter.WeightedCapacity != nil { + f2elemf1elem.WeightedCapacity = f2elemf1iter.WeightedCapacity + } + f2elemf1 = append(f2elemf1, *f2elemf1elem) + } + f2elem.Overrides = f2elemf1 + } + f2 = append(f2, *f2elem) + } + res.LaunchTemplateConfigs = f2 + } + if r.ko.Spec.OnDemandOptions != nil { + f3 := &svcsdktypes.OnDemandOptionsRequest{} + if r.ko.Spec.OnDemandOptions.AllocationStrategy != nil { + f3.AllocationStrategy = svcsdktypes.FleetOnDemandAllocationStrategy(*r.ko.Spec.OnDemandOptions.AllocationStrategy) + } + if r.ko.Spec.OnDemandOptions.CapacityReservationOptions != nil { + f3f1 := &svcsdktypes.CapacityReservationOptionsRequest{} + if r.ko.Spec.OnDemandOptions.CapacityReservationOptions.UsageStrategy != nil { + f3f1.UsageStrategy = svcsdktypes.FleetCapacityReservationUsageStrategy(*r.ko.Spec.OnDemandOptions.CapacityReservationOptions.UsageStrategy) + } + f3.CapacityReservationOptions = f3f1 + } + if r.ko.Spec.OnDemandOptions.MaxTotalPrice != nil { + f3.MaxTotalPrice = r.ko.Spec.OnDemandOptions.MaxTotalPrice + } + if r.ko.Spec.OnDemandOptions.MinTargetCapacity != nil { + minTargetCapacityCopy0 := *r.ko.Spec.OnDemandOptions.MinTargetCapacity + if minTargetCapacityCopy0 > math.MaxInt32 || minTargetCapacityCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field MinTargetCapacity is of type int32") + } + minTargetCapacityCopy := int32(minTargetCapacityCopy0) + f3.MinTargetCapacity = &minTargetCapacityCopy + } + if r.ko.Spec.OnDemandOptions.SingleAvailabilityZone != nil { + f3.SingleAvailabilityZone = r.ko.Spec.OnDemandOptions.SingleAvailabilityZone + } + if r.ko.Spec.OnDemandOptions.SingleInstanceType != nil { + f3.SingleInstanceType = r.ko.Spec.OnDemandOptions.SingleInstanceType + } + res.OnDemandOptions = f3 + } + if r.ko.Spec.ReplaceUnhealthyInstances != nil { + res.ReplaceUnhealthyInstances = r.ko.Spec.ReplaceUnhealthyInstances + } + if r.ko.Spec.SpotOptions != nil { + f5 := &svcsdktypes.SpotOptionsRequest{} + if r.ko.Spec.SpotOptions.AllocationStrategy != nil { + f5.AllocationStrategy = svcsdktypes.SpotAllocationStrategy(*r.ko.Spec.SpotOptions.AllocationStrategy) + } + if r.ko.Spec.SpotOptions.InstanceInterruptionBehavior != nil { + f5.InstanceInterruptionBehavior = svcsdktypes.SpotInstanceInterruptionBehavior(*r.ko.Spec.SpotOptions.InstanceInterruptionBehavior) + } + if r.ko.Spec.SpotOptions.InstancePoolsToUseCount != nil { + instancePoolsToUseCountCopy0 := *r.ko.Spec.SpotOptions.InstancePoolsToUseCount + if instancePoolsToUseCountCopy0 > math.MaxInt32 || instancePoolsToUseCountCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field InstancePoolsToUseCount is of type int32") + } + instancePoolsToUseCountCopy := int32(instancePoolsToUseCountCopy0) + f5.InstancePoolsToUseCount = &instancePoolsToUseCountCopy + } + if r.ko.Spec.SpotOptions.MaintenanceStrategies != nil { + f5f3 := &svcsdktypes.FleetSpotMaintenanceStrategiesRequest{} + if r.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance != nil { + f5f3f0 := &svcsdktypes.FleetSpotCapacityRebalanceRequest{} + if r.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.ReplacementStrategy != nil { + f5f3f0.ReplacementStrategy = svcsdktypes.FleetReplacementStrategy(*r.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.ReplacementStrategy) + } + if r.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.TerminationDelay != nil { + terminationDelayCopy0 := *r.ko.Spec.SpotOptions.MaintenanceStrategies.CapacityRebalance.TerminationDelay + if terminationDelayCopy0 > math.MaxInt32 || terminationDelayCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field TerminationDelay is of type int32") + } + terminationDelayCopy := int32(terminationDelayCopy0) + f5f3f0.TerminationDelay = &terminationDelayCopy + } + f5f3.CapacityRebalance = f5f3f0 + } + f5.MaintenanceStrategies = f5f3 + } + if r.ko.Spec.SpotOptions.MaxTotalPrice != nil { + f5.MaxTotalPrice = r.ko.Spec.SpotOptions.MaxTotalPrice + } + if r.ko.Spec.SpotOptions.MinTargetCapacity != nil { + minTargetCapacityCopy0 := *r.ko.Spec.SpotOptions.MinTargetCapacity + if minTargetCapacityCopy0 > math.MaxInt32 || minTargetCapacityCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field MinTargetCapacity is of type int32") + } + minTargetCapacityCopy := int32(minTargetCapacityCopy0) + f5.MinTargetCapacity = &minTargetCapacityCopy + } + if r.ko.Spec.SpotOptions.SingleAvailabilityZone != nil { + f5.SingleAvailabilityZone = r.ko.Spec.SpotOptions.SingleAvailabilityZone + } + if r.ko.Spec.SpotOptions.SingleInstanceType != nil { + f5.SingleInstanceType = r.ko.Spec.SpotOptions.SingleInstanceType + } + res.SpotOptions = f5 + } + if r.ko.Spec.TargetCapacitySpecification != nil { + f6 := &svcsdktypes.TargetCapacitySpecificationRequest{} + if r.ko.Spec.TargetCapacitySpecification.DefaultTargetCapacityType != nil { + f6.DefaultTargetCapacityType = svcsdktypes.DefaultTargetCapacityType(*r.ko.Spec.TargetCapacitySpecification.DefaultTargetCapacityType) + } + if r.ko.Spec.TargetCapacitySpecification.OnDemandTargetCapacity != nil { + onDemandTargetCapacityCopy0 := *r.ko.Spec.TargetCapacitySpecification.OnDemandTargetCapacity + if onDemandTargetCapacityCopy0 > math.MaxInt32 || onDemandTargetCapacityCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field OnDemandTargetCapacity is of type int32") + } + onDemandTargetCapacityCopy := int32(onDemandTargetCapacityCopy0) + f6.OnDemandTargetCapacity = &onDemandTargetCapacityCopy + } + if r.ko.Spec.TargetCapacitySpecification.SpotTargetCapacity != nil { + spotTargetCapacityCopy0 := *r.ko.Spec.TargetCapacitySpecification.SpotTargetCapacity + if spotTargetCapacityCopy0 > math.MaxInt32 || spotTargetCapacityCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field SpotTargetCapacity is of type int32") + } + spotTargetCapacityCopy := int32(spotTargetCapacityCopy0) + f6.SpotTargetCapacity = &spotTargetCapacityCopy + } + if r.ko.Spec.TargetCapacitySpecification.TargetCapacityUnitType != nil { + f6.TargetCapacityUnitType = svcsdktypes.TargetCapacityUnitType(*r.ko.Spec.TargetCapacitySpecification.TargetCapacityUnitType) + } + if r.ko.Spec.TargetCapacitySpecification.TotalTargetCapacity != nil { + totalTargetCapacityCopy0 := *r.ko.Spec.TargetCapacitySpecification.TotalTargetCapacity + if totalTargetCapacityCopy0 > math.MaxInt32 || totalTargetCapacityCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field TotalTargetCapacity is of type int32") + } + totalTargetCapacityCopy := int32(totalTargetCapacityCopy0) + f6.TotalTargetCapacity = &totalTargetCapacityCopy + } + res.TargetCapacitySpecification = f6 + } + if r.ko.Spec.TerminateInstancesWithExpiration != nil { + res.TerminateInstancesWithExpiration = r.ko.Spec.TerminateInstancesWithExpiration + } + if r.ko.Spec.Type != nil { + res.Type = svcsdktypes.FleetType(*r.ko.Spec.Type) + } + if r.ko.Spec.ValidFrom != nil { + res.ValidFrom = &r.ko.Spec.ValidFrom.Time + } + if r.ko.Spec.ValidUntil != nil { + res.ValidUntil = &r.ko.Spec.ValidUntil.Time + } + + return res, nil +} + +// sdkUpdate patches the supplied resource in the backend AWS service API and +// returns a new resource with updated fields. +func (rm *resourceManager) sdkUpdate( + ctx context.Context, + desired *resource, + latest *resource, + delta *ackcompare.Delta, +) (updated *resource, err error) { + rlog := ackrtlog.FromContext(ctx) + exit := rlog.Trace("rm.sdkUpdate") + defer func() { + exit(err) + }() + if delta.DifferentAt("Spec.Tags") { + if err := syncTags( + ctx, rm.sdkapi, rm.metrics, *latest.ko.Status.FleetID, + desired.ko.Spec.Tags, latest.ko.Spec.Tags, + ); err != nil { + return nil, err + } + } + + if !delta.DifferentExcept("Spec.Tags") { + return desired, nil + } + + // Only tag updates are supported in Fleets of type instant + if *latest.ko.Spec.Type == "instant" { + msg := "api error Unsupported: Fleets of type 'instant' cannot be modified." + return nil, ackerr.NewTerminalError(fmt.Errorf("%s", msg)) + } + + // Throw error if an immutable field is updated in the CRD + // The immutableFieldChanges function mentioned in https://aws-controllers-k8s.github.io/community/docs/contributor-docs/code-generator-config/#is_immutable-mutable-vs-immutable-fields does not seem to be working + immutable_fields := []string{"Spec.Type", "Spec.ReplaceUnhealthyInstances", "Spec.TerminateInstancesWithExpiration", "Spec.TargetCapacitySpecification.DefaultTargetCapacityType", "Spec.SpotOptions", "Spec.OnDemandOptions"} + for _, field := range immutable_fields { + if delta.DifferentAt(field) { + // Throw a Terminal Error if immutable fields are modified + msg := "field " + field + " is not updatable after fleet creation" + return nil, ackerr.NewTerminalError(fmt.Errorf("%s", msg)) + } + } + + // This value is automatically populated in TargetCapacitySpecification, but is not supported in ModifyFleetRequest + desired.ko.Spec.TargetCapacitySpecification.DefaultTargetCapacityType = nil + + // Ensure Launch Template Version is int and not $Latest/$Default + // Preventing those values as as those strings are updated in the backend with the ints they represent + // This confuses the reconciliation as the aws state falls out of sync with the CRD + // If we stick to int strings, all works smoothly + for _, config := range desired.ko.Spec.LaunchTemplateConfigs { + if config.LaunchTemplateSpecification != nil { + _, err := strconv.Atoi(*config.LaunchTemplateSpecification.Version) + if err != nil { + msg := "Only int values are supported for Launch Template Version in EC2 fleet spec" + return nil, ackerr.NewTerminalError(fmt.Errorf("%s", msg)) + } + } + } + + input, err := rm.newUpdateRequestPayload(ctx, desired, delta) + if err != nil { + return nil, err + } + + var resp *svcsdk.ModifyFleetOutput + _ = resp + resp, err = rm.sdkapi.ModifyFleet(ctx, input) + rm.metrics.RecordAPICall("UPDATE", "ModifyFleet", err) + if err != nil { + return nil, err + } + // Merge in the information we read from the API call above to the copy of + // the original Kubernetes object we passed to the function + ko := desired.ko.DeepCopy() + + // Modify Fleet doesn't return an updated Fleet object, so we need to set the state to "modifying" to reflect that the update is in progress + ko.Status.FleetState = aws.String("modifying") + + rm.setStatusDefaults(ko) + return &resource{ko}, nil +} + +// newUpdateRequestPayload returns an SDK-specific struct for the HTTP request +// payload of the Update API call for the resource +func (rm *resourceManager) newUpdateRequestPayload( + ctx context.Context, + r *resource, + delta *ackcompare.Delta, +) (*svcsdk.ModifyFleetInput, error) { + res := &svcsdk.ModifyFleetInput{} + + if r.ko.Spec.Context != nil { + res.Context = r.ko.Spec.Context + } + if r.ko.Spec.ExcessCapacityTerminationPolicy != nil { + res.ExcessCapacityTerminationPolicy = svcsdktypes.FleetExcessCapacityTerminationPolicy(*r.ko.Spec.ExcessCapacityTerminationPolicy) + } + if r.ko.Status.FleetID != nil { + res.FleetId = r.ko.Status.FleetID + } + if r.ko.Spec.LaunchTemplateConfigs != nil { + f4 := []svcsdktypes.FleetLaunchTemplateConfigRequest{} + for _, f4iter := range r.ko.Spec.LaunchTemplateConfigs { + f4elem := &svcsdktypes.FleetLaunchTemplateConfigRequest{} + if f4iter.LaunchTemplateSpecification != nil { + f4elemf0 := &svcsdktypes.FleetLaunchTemplateSpecificationRequest{} + if f4iter.LaunchTemplateSpecification.LaunchTemplateID != nil { + f4elemf0.LaunchTemplateId = f4iter.LaunchTemplateSpecification.LaunchTemplateID + } + if f4iter.LaunchTemplateSpecification.LaunchTemplateName != nil { + f4elemf0.LaunchTemplateName = f4iter.LaunchTemplateSpecification.LaunchTemplateName + } + if f4iter.LaunchTemplateSpecification.Version != nil { + f4elemf0.Version = f4iter.LaunchTemplateSpecification.Version + } + f4elem.LaunchTemplateSpecification = f4elemf0 + } + if f4iter.Overrides != nil { + f4elemf1 := []svcsdktypes.FleetLaunchTemplateOverridesRequest{} + for _, f4elemf1iter := range f4iter.Overrides { + f4elemf1elem := &svcsdktypes.FleetLaunchTemplateOverridesRequest{} + if f4elemf1iter.AvailabilityZone != nil { + f4elemf1elem.AvailabilityZone = f4elemf1iter.AvailabilityZone + } + if f4elemf1iter.BlockDeviceMappings != nil { + f4elemf1elemf1 := []svcsdktypes.FleetBlockDeviceMappingRequest{} + for _, f4elemf1elemf1iter := range f4elemf1iter.BlockDeviceMappings { + f4elemf1elemf1elem := &svcsdktypes.FleetBlockDeviceMappingRequest{} + if f4elemf1elemf1iter.DeviceName != nil { + f4elemf1elemf1elem.DeviceName = f4elemf1elemf1iter.DeviceName + } + if f4elemf1elemf1iter.EBS != nil { + f4elemf1elemf1elemf1 := &svcsdktypes.FleetEbsBlockDeviceRequest{} + if f4elemf1elemf1iter.EBS.DeleteOnTermination != nil { + f4elemf1elemf1elemf1.DeleteOnTermination = f4elemf1elemf1iter.EBS.DeleteOnTermination + } + if f4elemf1elemf1iter.EBS.Encrypted != nil { + f4elemf1elemf1elemf1.Encrypted = f4elemf1elemf1iter.EBS.Encrypted + } + if f4elemf1elemf1iter.EBS.IOPS != nil { + iopsCopy0 := *f4elemf1elemf1iter.EBS.IOPS + if iopsCopy0 > math.MaxInt32 || iopsCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Iops is of type int32") + } + iopsCopy := int32(iopsCopy0) + f4elemf1elemf1elemf1.Iops = &iopsCopy + } + if f4elemf1elemf1iter.EBS.KMSKeyID != nil { + f4elemf1elemf1elemf1.KmsKeyId = f4elemf1elemf1iter.EBS.KMSKeyID + } + if f4elemf1elemf1iter.EBS.SnapshotID != nil { + f4elemf1elemf1elemf1.SnapshotId = f4elemf1elemf1iter.EBS.SnapshotID + } + if f4elemf1elemf1iter.EBS.Throughput != nil { + throughputCopy0 := *f4elemf1elemf1iter.EBS.Throughput + if throughputCopy0 > math.MaxInt32 || throughputCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Throughput is of type int32") + } + throughputCopy := int32(throughputCopy0) + f4elemf1elemf1elemf1.Throughput = &throughputCopy + } + if f4elemf1elemf1iter.EBS.VolumeSize != nil { + volumeSizeCopy0 := *f4elemf1elemf1iter.EBS.VolumeSize + if volumeSizeCopy0 > math.MaxInt32 || volumeSizeCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field VolumeSize is of type int32") + } + volumeSizeCopy := int32(volumeSizeCopy0) + f4elemf1elemf1elemf1.VolumeSize = &volumeSizeCopy + } + if f4elemf1elemf1iter.EBS.VolumeType != nil { + f4elemf1elemf1elemf1.VolumeType = svcsdktypes.VolumeType(*f4elemf1elemf1iter.EBS.VolumeType) + } + f4elemf1elemf1elem.Ebs = f4elemf1elemf1elemf1 + } + if f4elemf1elemf1iter.NoDevice != nil { + f4elemf1elemf1elem.NoDevice = f4elemf1elemf1iter.NoDevice + } + if f4elemf1elemf1iter.VirtualName != nil { + f4elemf1elemf1elem.VirtualName = f4elemf1elemf1iter.VirtualName + } + f4elemf1elemf1 = append(f4elemf1elemf1, *f4elemf1elemf1elem) + } + f4elemf1elem.BlockDeviceMappings = f4elemf1elemf1 + } + if f4elemf1iter.ImageID != nil { + f4elemf1elem.ImageId = f4elemf1iter.ImageID + } + if f4elemf1iter.InstanceRequirements != nil { + f4elemf1elemf3 := &svcsdktypes.InstanceRequirementsRequest{} + if f4elemf1iter.InstanceRequirements.AcceleratorCount != nil { + f4elemf1elemf3f0 := &svcsdktypes.AcceleratorCountRequest{} + if f4elemf1iter.InstanceRequirements.AcceleratorCount.Max != nil { + maxCopy0 := *f4elemf1iter.InstanceRequirements.AcceleratorCount.Max + if maxCopy0 > math.MaxInt32 || maxCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Max is of type int32") + } + maxCopy := int32(maxCopy0) + f4elemf1elemf3f0.Max = &maxCopy + } + if f4elemf1iter.InstanceRequirements.AcceleratorCount.Min != nil { + minCopy0 := *f4elemf1iter.InstanceRequirements.AcceleratorCount.Min + if minCopy0 > math.MaxInt32 || minCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Min is of type int32") + } + minCopy := int32(minCopy0) + f4elemf1elemf3f0.Min = &minCopy + } + f4elemf1elemf3.AcceleratorCount = f4elemf1elemf3f0 + } + if f4elemf1iter.InstanceRequirements.AcceleratorManufacturers != nil { + f4elemf1elemf3f1 := []svcsdktypes.AcceleratorManufacturer{} + for _, f4elemf1elemf3f1iter := range f4elemf1iter.InstanceRequirements.AcceleratorManufacturers { + var f4elemf1elemf3f1elem string + f4elemf1elemf3f1elem = string(*f4elemf1elemf3f1iter) + f4elemf1elemf3f1 = append(f4elemf1elemf3f1, svcsdktypes.AcceleratorManufacturer(f4elemf1elemf3f1elem)) + } + f4elemf1elemf3.AcceleratorManufacturers = f4elemf1elemf3f1 + } + if f4elemf1iter.InstanceRequirements.AcceleratorNames != nil { + f4elemf1elemf3f2 := []svcsdktypes.AcceleratorName{} + for _, f4elemf1elemf3f2iter := range f4elemf1iter.InstanceRequirements.AcceleratorNames { + var f4elemf1elemf3f2elem string + f4elemf1elemf3f2elem = string(*f4elemf1elemf3f2iter) + f4elemf1elemf3f2 = append(f4elemf1elemf3f2, svcsdktypes.AcceleratorName(f4elemf1elemf3f2elem)) + } + f4elemf1elemf3.AcceleratorNames = f4elemf1elemf3f2 + } + if f4elemf1iter.InstanceRequirements.AcceleratorTotalMemoryMiB != nil { + f4elemf1elemf3f3 := &svcsdktypes.AcceleratorTotalMemoryMiBRequest{} + if f4elemf1iter.InstanceRequirements.AcceleratorTotalMemoryMiB.Max != nil { + maxCopy0 := *f4elemf1iter.InstanceRequirements.AcceleratorTotalMemoryMiB.Max + if maxCopy0 > math.MaxInt32 || maxCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Max is of type int32") + } + maxCopy := int32(maxCopy0) + f4elemf1elemf3f3.Max = &maxCopy + } + if f4elemf1iter.InstanceRequirements.AcceleratorTotalMemoryMiB.Min != nil { + minCopy0 := *f4elemf1iter.InstanceRequirements.AcceleratorTotalMemoryMiB.Min + if minCopy0 > math.MaxInt32 || minCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Min is of type int32") + } + minCopy := int32(minCopy0) + f4elemf1elemf3f3.Min = &minCopy + } + f4elemf1elemf3.AcceleratorTotalMemoryMiB = f4elemf1elemf3f3 + } + if f4elemf1iter.InstanceRequirements.AcceleratorTypes != nil { + f4elemf1elemf3f4 := []svcsdktypes.AcceleratorType{} + for _, f4elemf1elemf3f4iter := range f4elemf1iter.InstanceRequirements.AcceleratorTypes { + var f4elemf1elemf3f4elem string + f4elemf1elemf3f4elem = string(*f4elemf1elemf3f4iter) + f4elemf1elemf3f4 = append(f4elemf1elemf3f4, svcsdktypes.AcceleratorType(f4elemf1elemf3f4elem)) + } + f4elemf1elemf3.AcceleratorTypes = f4elemf1elemf3f4 + } + if f4elemf1iter.InstanceRequirements.AllowedInstanceTypes != nil { + f4elemf1elemf3.AllowedInstanceTypes = aws.ToStringSlice(f4elemf1iter.InstanceRequirements.AllowedInstanceTypes) + } + if f4elemf1iter.InstanceRequirements.BareMetal != nil { + f4elemf1elemf3.BareMetal = svcsdktypes.BareMetal(*f4elemf1iter.InstanceRequirements.BareMetal) + } + if f4elemf1iter.InstanceRequirements.BaselineEBSBandwidthMbps != nil { + f4elemf1elemf3f7 := &svcsdktypes.BaselineEbsBandwidthMbpsRequest{} + if f4elemf1iter.InstanceRequirements.BaselineEBSBandwidthMbps.Max != nil { + maxCopy0 := *f4elemf1iter.InstanceRequirements.BaselineEBSBandwidthMbps.Max + if maxCopy0 > math.MaxInt32 || maxCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Max is of type int32") + } + maxCopy := int32(maxCopy0) + f4elemf1elemf3f7.Max = &maxCopy + } + if f4elemf1iter.InstanceRequirements.BaselineEBSBandwidthMbps.Min != nil { + minCopy0 := *f4elemf1iter.InstanceRequirements.BaselineEBSBandwidthMbps.Min + if minCopy0 > math.MaxInt32 || minCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Min is of type int32") + } + minCopy := int32(minCopy0) + f4elemf1elemf3f7.Min = &minCopy + } + f4elemf1elemf3.BaselineEbsBandwidthMbps = f4elemf1elemf3f7 + } + if f4elemf1iter.InstanceRequirements.BaselinePerformanceFactors != nil { + f4elemf1elemf3f8 := &svcsdktypes.BaselinePerformanceFactorsRequest{} + if f4elemf1iter.InstanceRequirements.BaselinePerformanceFactors.CPU != nil { + f4elemf1elemf3f8f0 := &svcsdktypes.CpuPerformanceFactorRequest{} + if f4elemf1iter.InstanceRequirements.BaselinePerformanceFactors.CPU.References != nil { + f4elemf1elemf3f8f0f0 := []svcsdktypes.PerformanceFactorReferenceRequest{} + for _, f4elemf1elemf3f8f0f0iter := range f4elemf1iter.InstanceRequirements.BaselinePerformanceFactors.CPU.References { + f4elemf1elemf3f8f0f0elem := &svcsdktypes.PerformanceFactorReferenceRequest{} + if f4elemf1elemf3f8f0f0iter.InstanceFamily != nil { + f4elemf1elemf3f8f0f0elem.InstanceFamily = f4elemf1elemf3f8f0f0iter.InstanceFamily + } + f4elemf1elemf3f8f0f0 = append(f4elemf1elemf3f8f0f0, *f4elemf1elemf3f8f0f0elem) + } + f4elemf1elemf3f8f0.References = f4elemf1elemf3f8f0f0 + } + f4elemf1elemf3f8.Cpu = f4elemf1elemf3f8f0 + } + f4elemf1elemf3.BaselinePerformanceFactors = f4elemf1elemf3f8 + } + if f4elemf1iter.InstanceRequirements.BurstablePerformance != nil { + f4elemf1elemf3.BurstablePerformance = svcsdktypes.BurstablePerformance(*f4elemf1iter.InstanceRequirements.BurstablePerformance) + } + if f4elemf1iter.InstanceRequirements.CPUManufacturers != nil { + f4elemf1elemf3f10 := []svcsdktypes.CpuManufacturer{} + for _, f4elemf1elemf3f10iter := range f4elemf1iter.InstanceRequirements.CPUManufacturers { + var f4elemf1elemf3f10elem string + f4elemf1elemf3f10elem = string(*f4elemf1elemf3f10iter) + f4elemf1elemf3f10 = append(f4elemf1elemf3f10, svcsdktypes.CpuManufacturer(f4elemf1elemf3f10elem)) + } + f4elemf1elemf3.CpuManufacturers = f4elemf1elemf3f10 + } + if f4elemf1iter.InstanceRequirements.ExcludedInstanceTypes != nil { + f4elemf1elemf3.ExcludedInstanceTypes = aws.ToStringSlice(f4elemf1iter.InstanceRequirements.ExcludedInstanceTypes) + } + if f4elemf1iter.InstanceRequirements.InstanceGenerations != nil { + f4elemf1elemf3f12 := []svcsdktypes.InstanceGeneration{} + for _, f4elemf1elemf3f12iter := range f4elemf1iter.InstanceRequirements.InstanceGenerations { + var f4elemf1elemf3f12elem string + f4elemf1elemf3f12elem = string(*f4elemf1elemf3f12iter) + f4elemf1elemf3f12 = append(f4elemf1elemf3f12, svcsdktypes.InstanceGeneration(f4elemf1elemf3f12elem)) + } + f4elemf1elemf3.InstanceGenerations = f4elemf1elemf3f12 + } + if f4elemf1iter.InstanceRequirements.LocalStorage != nil { + f4elemf1elemf3.LocalStorage = svcsdktypes.LocalStorage(*f4elemf1iter.InstanceRequirements.LocalStorage) + } + if f4elemf1iter.InstanceRequirements.LocalStorageTypes != nil { + f4elemf1elemf3f14 := []svcsdktypes.LocalStorageType{} + for _, f4elemf1elemf3f14iter := range f4elemf1iter.InstanceRequirements.LocalStorageTypes { + var f4elemf1elemf3f14elem string + f4elemf1elemf3f14elem = string(*f4elemf1elemf3f14iter) + f4elemf1elemf3f14 = append(f4elemf1elemf3f14, svcsdktypes.LocalStorageType(f4elemf1elemf3f14elem)) + } + f4elemf1elemf3.LocalStorageTypes = f4elemf1elemf3f14 + } + if f4elemf1iter.InstanceRequirements.MaxSpotPriceAsPercentageOfOptimalOnDemandPrice != nil { + maxSpotPriceAsPercentageOfOptimalOnDemandPriceCopy0 := *f4elemf1iter.InstanceRequirements.MaxSpotPriceAsPercentageOfOptimalOnDemandPrice + if maxSpotPriceAsPercentageOfOptimalOnDemandPriceCopy0 > math.MaxInt32 || maxSpotPriceAsPercentageOfOptimalOnDemandPriceCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field MaxSpotPriceAsPercentageOfOptimalOnDemandPrice is of type int32") + } + maxSpotPriceAsPercentageOfOptimalOnDemandPriceCopy := int32(maxSpotPriceAsPercentageOfOptimalOnDemandPriceCopy0) + f4elemf1elemf3.MaxSpotPriceAsPercentageOfOptimalOnDemandPrice = &maxSpotPriceAsPercentageOfOptimalOnDemandPriceCopy + } + if f4elemf1iter.InstanceRequirements.MemoryGiBPerVCPU != nil { + f4elemf1elemf3f16 := &svcsdktypes.MemoryGiBPerVCpuRequest{} + if f4elemf1iter.InstanceRequirements.MemoryGiBPerVCPU.Max != nil { + f4elemf1elemf3f16.Max = f4elemf1iter.InstanceRequirements.MemoryGiBPerVCPU.Max + } + if f4elemf1iter.InstanceRequirements.MemoryGiBPerVCPU.Min != nil { + f4elemf1elemf3f16.Min = f4elemf1iter.InstanceRequirements.MemoryGiBPerVCPU.Min + } + f4elemf1elemf3.MemoryGiBPerVCpu = f4elemf1elemf3f16 + } + if f4elemf1iter.InstanceRequirements.MemoryMiB != nil { + f4elemf1elemf3f17 := &svcsdktypes.MemoryMiBRequest{} + if f4elemf1iter.InstanceRequirements.MemoryMiB.Max != nil { + maxCopy0 := *f4elemf1iter.InstanceRequirements.MemoryMiB.Max + if maxCopy0 > math.MaxInt32 || maxCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Max is of type int32") + } + maxCopy := int32(maxCopy0) + f4elemf1elemf3f17.Max = &maxCopy + } + if f4elemf1iter.InstanceRequirements.MemoryMiB.Min != nil { + minCopy0 := *f4elemf1iter.InstanceRequirements.MemoryMiB.Min + if minCopy0 > math.MaxInt32 || minCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Min is of type int32") + } + minCopy := int32(minCopy0) + f4elemf1elemf3f17.Min = &minCopy + } + f4elemf1elemf3.MemoryMiB = f4elemf1elemf3f17 + } + if f4elemf1iter.InstanceRequirements.NetworkBandwidthGbps != nil { + f4elemf1elemf3f18 := &svcsdktypes.NetworkBandwidthGbpsRequest{} + if f4elemf1iter.InstanceRequirements.NetworkBandwidthGbps.Max != nil { + f4elemf1elemf3f18.Max = f4elemf1iter.InstanceRequirements.NetworkBandwidthGbps.Max + } + if f4elemf1iter.InstanceRequirements.NetworkBandwidthGbps.Min != nil { + f4elemf1elemf3f18.Min = f4elemf1iter.InstanceRequirements.NetworkBandwidthGbps.Min + } + f4elemf1elemf3.NetworkBandwidthGbps = f4elemf1elemf3f18 + } + if f4elemf1iter.InstanceRequirements.NetworkInterfaceCount != nil { + f4elemf1elemf3f19 := &svcsdktypes.NetworkInterfaceCountRequest{} + if f4elemf1iter.InstanceRequirements.NetworkInterfaceCount.Max != nil { + maxCopy0 := *f4elemf1iter.InstanceRequirements.NetworkInterfaceCount.Max + if maxCopy0 > math.MaxInt32 || maxCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Max is of type int32") + } + maxCopy := int32(maxCopy0) + f4elemf1elemf3f19.Max = &maxCopy + } + if f4elemf1iter.InstanceRequirements.NetworkInterfaceCount.Min != nil { + minCopy0 := *f4elemf1iter.InstanceRequirements.NetworkInterfaceCount.Min + if minCopy0 > math.MaxInt32 || minCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Min is of type int32") + } + minCopy := int32(minCopy0) + f4elemf1elemf3f19.Min = &minCopy + } + f4elemf1elemf3.NetworkInterfaceCount = f4elemf1elemf3f19 + } + if f4elemf1iter.InstanceRequirements.OnDemandMaxPricePercentageOverLowestPrice != nil { + onDemandMaxPricePercentageOverLowestPriceCopy0 := *f4elemf1iter.InstanceRequirements.OnDemandMaxPricePercentageOverLowestPrice + if onDemandMaxPricePercentageOverLowestPriceCopy0 > math.MaxInt32 || onDemandMaxPricePercentageOverLowestPriceCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field OnDemandMaxPricePercentageOverLowestPrice is of type int32") + } + onDemandMaxPricePercentageOverLowestPriceCopy := int32(onDemandMaxPricePercentageOverLowestPriceCopy0) + f4elemf1elemf3.OnDemandMaxPricePercentageOverLowestPrice = &onDemandMaxPricePercentageOverLowestPriceCopy + } + if f4elemf1iter.InstanceRequirements.RequireHibernateSupport != nil { + f4elemf1elemf3.RequireHibernateSupport = f4elemf1iter.InstanceRequirements.RequireHibernateSupport + } + if f4elemf1iter.InstanceRequirements.SpotMaxPricePercentageOverLowestPrice != nil { + spotMaxPricePercentageOverLowestPriceCopy0 := *f4elemf1iter.InstanceRequirements.SpotMaxPricePercentageOverLowestPrice + if spotMaxPricePercentageOverLowestPriceCopy0 > math.MaxInt32 || spotMaxPricePercentageOverLowestPriceCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field SpotMaxPricePercentageOverLowestPrice is of type int32") + } + spotMaxPricePercentageOverLowestPriceCopy := int32(spotMaxPricePercentageOverLowestPriceCopy0) + f4elemf1elemf3.SpotMaxPricePercentageOverLowestPrice = &spotMaxPricePercentageOverLowestPriceCopy + } + if f4elemf1iter.InstanceRequirements.TotalLocalStorageGB != nil { + f4elemf1elemf3f23 := &svcsdktypes.TotalLocalStorageGBRequest{} + if f4elemf1iter.InstanceRequirements.TotalLocalStorageGB.Max != nil { + f4elemf1elemf3f23.Max = f4elemf1iter.InstanceRequirements.TotalLocalStorageGB.Max + } + if f4elemf1iter.InstanceRequirements.TotalLocalStorageGB.Min != nil { + f4elemf1elemf3f23.Min = f4elemf1iter.InstanceRequirements.TotalLocalStorageGB.Min + } + f4elemf1elemf3.TotalLocalStorageGB = f4elemf1elemf3f23 + } + if f4elemf1iter.InstanceRequirements.VCPUCount != nil { + f4elemf1elemf3f24 := &svcsdktypes.VCpuCountRangeRequest{} + if f4elemf1iter.InstanceRequirements.VCPUCount.Max != nil { + maxCopy0 := *f4elemf1iter.InstanceRequirements.VCPUCount.Max + if maxCopy0 > math.MaxInt32 || maxCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Max is of type int32") + } + maxCopy := int32(maxCopy0) + f4elemf1elemf3f24.Max = &maxCopy + } + if f4elemf1iter.InstanceRequirements.VCPUCount.Min != nil { + minCopy0 := *f4elemf1iter.InstanceRequirements.VCPUCount.Min + if minCopy0 > math.MaxInt32 || minCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field Min is of type int32") + } + minCopy := int32(minCopy0) + f4elemf1elemf3f24.Min = &minCopy + } + f4elemf1elemf3.VCpuCount = f4elemf1elemf3f24 + } + f4elemf1elem.InstanceRequirements = f4elemf1elemf3 + } + if f4elemf1iter.InstanceType != nil { + f4elemf1elem.InstanceType = svcsdktypes.InstanceType(*f4elemf1iter.InstanceType) + } + if f4elemf1iter.MaxPrice != nil { + f4elemf1elem.MaxPrice = f4elemf1iter.MaxPrice + } + if f4elemf1iter.Placement != nil { + f4elemf1elemf6 := &svcsdktypes.Placement{} + if f4elemf1iter.Placement.Affinity != nil { + f4elemf1elemf6.Affinity = f4elemf1iter.Placement.Affinity + } + if f4elemf1iter.Placement.AvailabilityZone != nil { + f4elemf1elemf6.AvailabilityZone = f4elemf1iter.Placement.AvailabilityZone + } + if f4elemf1iter.Placement.GroupName != nil { + f4elemf1elemf6.GroupName = f4elemf1iter.Placement.GroupName + } + if f4elemf1iter.Placement.HostID != nil { + f4elemf1elemf6.HostId = f4elemf1iter.Placement.HostID + } + if f4elemf1iter.Placement.HostResourceGroupARN != nil { + f4elemf1elemf6.HostResourceGroupArn = f4elemf1iter.Placement.HostResourceGroupARN + } + if f4elemf1iter.Placement.PartitionNumber != nil { + partitionNumberCopy0 := *f4elemf1iter.Placement.PartitionNumber + if partitionNumberCopy0 > math.MaxInt32 || partitionNumberCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field PartitionNumber is of type int32") + } + partitionNumberCopy := int32(partitionNumberCopy0) + f4elemf1elemf6.PartitionNumber = &partitionNumberCopy + } + if f4elemf1iter.Placement.SpreadDomain != nil { + f4elemf1elemf6.SpreadDomain = f4elemf1iter.Placement.SpreadDomain + } + if f4elemf1iter.Placement.Tenancy != nil { + f4elemf1elemf6.Tenancy = svcsdktypes.Tenancy(*f4elemf1iter.Placement.Tenancy) + } + f4elemf1elem.Placement = f4elemf1elemf6 + } + if f4elemf1iter.Priority != nil { + f4elemf1elem.Priority = f4elemf1iter.Priority + } + if f4elemf1iter.SubnetID != nil { + f4elemf1elem.SubnetId = f4elemf1iter.SubnetID + } + if f4elemf1iter.WeightedCapacity != nil { + f4elemf1elem.WeightedCapacity = f4elemf1iter.WeightedCapacity + } + f4elemf1 = append(f4elemf1, *f4elemf1elem) + } + f4elem.Overrides = f4elemf1 + } + f4 = append(f4, *f4elem) + } + res.LaunchTemplateConfigs = f4 + } + if r.ko.Spec.TargetCapacitySpecification != nil { + f5 := &svcsdktypes.TargetCapacitySpecificationRequest{} + if r.ko.Spec.TargetCapacitySpecification.DefaultTargetCapacityType != nil { + f5.DefaultTargetCapacityType = svcsdktypes.DefaultTargetCapacityType(*r.ko.Spec.TargetCapacitySpecification.DefaultTargetCapacityType) + } + if r.ko.Spec.TargetCapacitySpecification.OnDemandTargetCapacity != nil { + onDemandTargetCapacityCopy0 := *r.ko.Spec.TargetCapacitySpecification.OnDemandTargetCapacity + if onDemandTargetCapacityCopy0 > math.MaxInt32 || onDemandTargetCapacityCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field OnDemandTargetCapacity is of type int32") + } + onDemandTargetCapacityCopy := int32(onDemandTargetCapacityCopy0) + f5.OnDemandTargetCapacity = &onDemandTargetCapacityCopy + } + if r.ko.Spec.TargetCapacitySpecification.SpotTargetCapacity != nil { + spotTargetCapacityCopy0 := *r.ko.Spec.TargetCapacitySpecification.SpotTargetCapacity + if spotTargetCapacityCopy0 > math.MaxInt32 || spotTargetCapacityCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field SpotTargetCapacity is of type int32") + } + spotTargetCapacityCopy := int32(spotTargetCapacityCopy0) + f5.SpotTargetCapacity = &spotTargetCapacityCopy + } + if r.ko.Spec.TargetCapacitySpecification.TargetCapacityUnitType != nil { + f5.TargetCapacityUnitType = svcsdktypes.TargetCapacityUnitType(*r.ko.Spec.TargetCapacitySpecification.TargetCapacityUnitType) + } + if r.ko.Spec.TargetCapacitySpecification.TotalTargetCapacity != nil { + totalTargetCapacityCopy0 := *r.ko.Spec.TargetCapacitySpecification.TotalTargetCapacity + if totalTargetCapacityCopy0 > math.MaxInt32 || totalTargetCapacityCopy0 < math.MinInt32 { + return nil, fmt.Errorf("error: field TotalTargetCapacity is of type int32") + } + totalTargetCapacityCopy := int32(totalTargetCapacityCopy0) + f5.TotalTargetCapacity = &totalTargetCapacityCopy + } + res.TargetCapacitySpecification = f5 + } + + return res, nil +} + +// sdkDelete deletes the supplied resource in the backend AWS service API +func (rm *resourceManager) sdkDelete( + ctx context.Context, + r *resource, +) (latest *resource, err error) { + rlog := ackrtlog.FromContext(ctx) + exit := rlog.Trace("rm.sdkDelete") + defer func() { + exit(err) + }() + if fleetDeleting(r) { + return r, requeueWaitWhileDeleting + } + input, err := rm.newDeleteRequestPayload(r) + if err != nil { + return nil, err + } + if err = addIDToDeleteRequest(r, input); err != nil { + return nil, ackerr.NotFound + } + + if r.ko.Spec.TerminateInstancesOnDeletion != nil { + input.TerminateInstances = r.ko.Spec.TerminateInstancesOnDeletion + } else { + // Default TerminateInstances = true on DeleteFleets requests to prevent orphaned instances + input.TerminateInstances = aws.Bool(true) + } + var resp *svcsdk.DeleteFleetsOutput + _ = resp + resp, err = rm.sdkapi.DeleteFleets(ctx, input) + rm.metrics.RecordAPICall("DELETE", "DeleteFleets", err) + return nil, err +} + +// newDeleteRequestPayload returns an SDK-specific struct for the HTTP request +// payload of the Delete API call for the resource +func (rm *resourceManager) newDeleteRequestPayload( + r *resource, +) (*svcsdk.DeleteFleetsInput, error) { + res := &svcsdk.DeleteFleetsInput{} + + return res, nil +} + +// setStatusDefaults sets default properties into supplied custom resource +func (rm *resourceManager) setStatusDefaults( + ko *svcapitypes.Fleet, +) { + if ko.Status.ACKResourceMetadata == nil { + ko.Status.ACKResourceMetadata = &ackv1alpha1.ResourceMetadata{} + } + if ko.Status.ACKResourceMetadata.Region == nil { + ko.Status.ACKResourceMetadata.Region = &rm.awsRegion + } + if ko.Status.ACKResourceMetadata.OwnerAccountID == nil { + ko.Status.ACKResourceMetadata.OwnerAccountID = &rm.awsAccountID + } + if ko.Status.Conditions == nil { + ko.Status.Conditions = []*ackv1alpha1.Condition{} + } +} + +// updateConditions returns updated resource, true; if conditions were updated +// else it returns nil, false +func (rm *resourceManager) updateConditions( + r *resource, + onSuccess bool, + err error, +) (*resource, bool) { + ko := r.ko.DeepCopy() + rm.setStatusDefaults(ko) + + // Terminal condition + var terminalCondition *ackv1alpha1.Condition = nil + var recoverableCondition *ackv1alpha1.Condition = nil + var syncCondition *ackv1alpha1.Condition = nil + for _, condition := range ko.Status.Conditions { + if condition.Type == ackv1alpha1.ConditionTypeTerminal { + terminalCondition = condition + } + if condition.Type == ackv1alpha1.ConditionTypeRecoverable { + recoverableCondition = condition + } + if condition.Type == ackv1alpha1.ConditionTypeResourceSynced { + syncCondition = condition + } + } + var termError *ackerr.TerminalError + if rm.terminalAWSError(err) || err == ackerr.SecretTypeNotSupported || err == ackerr.SecretNotFound || errors.As(err, &termError) { + if terminalCondition == nil { + terminalCondition = &ackv1alpha1.Condition{ + Type: ackv1alpha1.ConditionTypeTerminal, + } + ko.Status.Conditions = append(ko.Status.Conditions, terminalCondition) + } + var errorMessage = "" + if err == ackerr.SecretTypeNotSupported || err == ackerr.SecretNotFound || errors.As(err, &termError) { + errorMessage = err.Error() + } else { + awsErr, _ := ackerr.AWSError(err) + errorMessage = awsErr.Error() + } + terminalCondition.Status = corev1.ConditionTrue + terminalCondition.Message = &errorMessage + } else { + // Clear the terminal condition if no longer present + if terminalCondition != nil { + terminalCondition.Status = corev1.ConditionFalse + terminalCondition.Message = nil + } + // Handling Recoverable Conditions + if err != nil { + if recoverableCondition == nil { + // Add a new Condition containing a non-terminal error + recoverableCondition = &ackv1alpha1.Condition{ + Type: ackv1alpha1.ConditionTypeRecoverable, + } + ko.Status.Conditions = append(ko.Status.Conditions, recoverableCondition) + } + recoverableCondition.Status = corev1.ConditionTrue + awsErr, _ := ackerr.AWSError(err) + errorMessage := err.Error() + if awsErr != nil { + errorMessage = awsErr.Error() + } + recoverableCondition.Message = &errorMessage + } else if recoverableCondition != nil { + recoverableCondition.Status = corev1.ConditionFalse + recoverableCondition.Message = nil + } + } + // Required to avoid the "declared but not used" error in the default case + _ = syncCondition + if terminalCondition != nil || recoverableCondition != nil || syncCondition != nil { + return &resource{ko}, true // updated + } + return nil, false // not updated +} + +// terminalAWSError returns awserr, true; if the supplied error is an aws Error type +// and if the exception indicates that it is a Terminal exception +// 'Terminal' exception are specified in generator configuration +func (rm *resourceManager) terminalAWSError(err error) bool { + if err == nil { + return false + } + + var terminalErr smithy.APIError + if !errors.As(err, &terminalErr) { + return false + } + switch terminalErr.ErrorCode() { + case "InvalidParameterValue": + return true + default: + return false + } +} + +func (rm *resourceManager) newTag( + c svcapitypes.Tag, +) *svcsdktypes.Tag { + res := &svcsdktypes.Tag{} + if c.Key != nil { + res.Key = c.Key + } + if c.Value != nil { + res.Value = c.Value + } + + return res +} diff --git a/pkg/resource/fleet/tags.go b/pkg/resource/fleet/tags.go new file mode 100644 index 00000000..e954560f --- /dev/null +++ b/pkg/resource/fleet/tags.go @@ -0,0 +1,119 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + +package fleet + +import ( + "slices" + "strings" + + acktags "github.com/aws-controllers-k8s/runtime/pkg/tags" + + svcapitypes "github.com/aws-controllers-k8s/ec2-controller/apis/v1alpha1" +) + +var ( + _ = svcapitypes.Fleet{} + _ = acktags.NewTags() +) + +// convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. +// This method helps in creating the hub(acktags.Tags) for merging +// default controller tags with existing resource tags. It also returns a slice +// of keys maintaining the original key Order when the tags are a list +func convertToOrderedACKTags(tags []*svcapitypes.Tag) (acktags.Tags, []string) { + result := acktags.NewTags() + keyOrder := []string{} + + if len(tags) == 0 { + return result, keyOrder + } + for _, t := range tags { + if t.Key != nil { + keyOrder = append(keyOrder, *t.Key) + if t.Value != nil { + result[*t.Key] = *t.Value + } else { + result[*t.Key] = "" + } + } + } + + return result, keyOrder +} + +// fromACKTags converts the tags parameter into []*svcapitypes.Tag shape. +// This method helps in setting the tags back inside AWSResource after merging +// default controller tags with existing resource tags. When a list, +// it maintains the order from original +func fromACKTags(tags acktags.Tags, keyOrder []string) []*svcapitypes.Tag { + result := []*svcapitypes.Tag{} + + for _, k := range keyOrder { + v, ok := tags[k] + if ok { + tag := svcapitypes.Tag{Key: &k, Value: &v} + result = append(result, &tag) + delete(tags, k) + } + } + for k, v := range tags { + tag := svcapitypes.Tag{Key: &k, Value: &v} + result = append(result, &tag) + } + + return result +} + +// ignoreSystemTags ignores tags that have keys that start with "aws:" +// and systemTags defined on startup via the --resource-tags flag, +// to avoid patching them to the resourceSpec. +// Eg. resources created with cloudformation have tags that cannot be +// removed by an ACK controller +func ignoreSystemTags(tags acktags.Tags, systemTags []string) { + for k := range tags { + if strings.HasPrefix(k, "aws:") || + slices.Contains(systemTags, k) { + delete(tags, k) + } + } +} + +// syncAWSTags ensures AWS-managed tags (prefixed with "aws:") from the latest resource state +// are preserved in the desired state. This prevents the controller from attempting to +// modify AWS-managed tags, which would result in an error. +// +// AWS-managed tags are automatically added by AWS services (e.g., CloudFormation, Service Catalog) +// and cannot be modified or deleted through normal tag operations. Common examples include: +// - aws:cloudformation:stack-name +// - aws:servicecatalog:productArn +// +// Parameters: +// - a: The target Tags map to be updated (typically desired state) +// - b: The source Tags map containing AWS-managed tags (typically latest state) +// +// Example: +// +// latest := Tags{"aws:cloudformation:stack-name": "my-stack", "environment": "prod"} +// desired := Tags{"environment": "dev"} +// SyncAWSTags(desired, latest) +// desired now contains {"aws:cloudformation:stack-name": "my-stack", "environment": "dev"} +func syncAWSTags(a acktags.Tags, b acktags.Tags) { + for k := range b { + if strings.HasPrefix(k, "aws:") { + a[k] = b[k] + } + } +} diff --git a/templates/hooks/fleet/sdk_create_post_build_request.go.tpl b/templates/hooks/fleet/sdk_create_post_build_request.go.tpl new file mode 100644 index 00000000..6531c321 --- /dev/null +++ b/templates/hooks/fleet/sdk_create_post_build_request.go.tpl @@ -0,0 +1,17 @@ + updateTagSpecificationsInCreateRequest(desired, input) + + for _, config := range input.LaunchTemplateConfigs { + if config.LaunchTemplateSpecification != nil { + + // Ensure Launch Template Version is int and not $Latest/$Default + // Preventing those values as as those strings are updated in the backend with the ints they represent + // This confuses the reconciliation as the aws state falls out of sync with the CRD + // If we stick to int strings, all works smoothly + + _, err := strconv.Atoi(*config.LaunchTemplateSpecification.Version); + if err != nil { + msg := "Only int values are supported for Launch Template Version in EC2 fleet spec" + return nil, ackerr.NewTerminalError(fmt.Errorf("%s", msg)) + } + } + } \ No newline at end of file diff --git a/templates/hooks/fleet/sdk_delete_post_build_request.go.tpl b/templates/hooks/fleet/sdk_delete_post_build_request.go.tpl new file mode 100644 index 00000000..a6326fd7 --- /dev/null +++ b/templates/hooks/fleet/sdk_delete_post_build_request.go.tpl @@ -0,0 +1,10 @@ + if err = addIDToDeleteRequest(r, input); err != nil { + return nil, ackerr.NotFound + } + + if r.ko.Spec.TerminateInstancesOnDeletion != nil { + input.TerminateInstances = r.ko.Spec.TerminateInstancesOnDeletion + } else { + // Default TerminateInstances = true on DeleteFleets requests to prevent orphaned instances + input.TerminateInstances = aws.Bool(true) + } \ No newline at end of file diff --git a/templates/hooks/fleet/sdk_delete_pre_build_request.go.tpl b/templates/hooks/fleet/sdk_delete_pre_build_request.go.tpl new file mode 100644 index 00000000..2f247f63 --- /dev/null +++ b/templates/hooks/fleet/sdk_delete_pre_build_request.go.tpl @@ -0,0 +1,3 @@ + if fleetDeleting(r) { + return r, requeueWaitWhileDeleting + } \ No newline at end of file diff --git a/templates/hooks/fleet/sdk_file_end.go.tpl b/templates/hooks/fleet/sdk_file_end.go.tpl new file mode 100644 index 00000000..46340996 --- /dev/null +++ b/templates/hooks/fleet/sdk_file_end.go.tpl @@ -0,0 +1,23 @@ +{{ $CRD := .CRD }} +{{ $SDKAPI := .SDKAPI }} + +{{/* Generate helper methods for Fleet */}} +{{- range $specFieldName, $specField := $CRD.Config.Resources.Fleet.Fields }} +{{- if $specField.From }} +{{- $operationName := $specField.From.Operation }} +{{- $operation := (index $SDKAPI.API.Operations $operationName) -}} +{{- range $fleetRefName, $fleetMemberRefs := $operation.InputRef.Shape.MemberRefs -}} +{{- if eq $fleetRefName "Tags" }} +{{- $fleetRef := $fleetMemberRefs.Shape.MemberRef }} +{{- $fleetRefName = "Tag" }} +func (rm *resourceManager) new{{ $fleetRefName }}( + c svcapitypes.{{ $fleetRefName }}, +) *svcsdktypes.{{ $fleetRefName }} { + res := &svcsdktypes.{{ $fleetRefName }}{} +{{ GoCodeSetSDKForStruct $CRD "" "res" $fleetRef "" "c" 1 }} + return res +} +{{- end }} +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/templates/hooks/fleet/sdk_read_many_post_set_output.go.tpl b/templates/hooks/fleet/sdk_read_many_post_set_output.go.tpl new file mode 100644 index 00000000..47f48c38 --- /dev/null +++ b/templates/hooks/fleet/sdk_read_many_post_set_output.go.tpl @@ -0,0 +1,12 @@ + // Here we want to check if the fleet is deleted + // returning NotFound will trigger a create + if fleetDeleted(r) { + return nil, ackerr.NotFound + } + + toAdd, toDelete := computeTagsDelta(r.ko.Spec.Tags, ko.Spec.Tags) + if len(toAdd) == 0 && len(toDelete) == 0 { + // if resource's initial tags and response tags are equal, + // then assign resource's tags to maintain tag order + ko.Spec.Tags = r.ko.Spec.Tags + } diff --git a/templates/hooks/fleet/sdk_update_pre_build_request.go.tpl b/templates/hooks/fleet/sdk_update_pre_build_request.go.tpl new file mode 100644 index 00000000..95f93a60 --- /dev/null +++ b/templates/hooks/fleet/sdk_update_pre_build_request.go.tpl @@ -0,0 +1,47 @@ + if delta.DifferentAt("Spec.Tags") { + if err := syncTags( + ctx, rm.sdkapi, rm.metrics, *latest.ko.Status.FleetID, + desired.ko.Spec.Tags, latest.ko.Spec.Tags, + ); err != nil { + return nil, err + } + } + + if !delta.DifferentExcept("Spec.Tags") { + return desired, nil + } + + // Only tag updates are supported in Fleets of type instant + if *latest.ko.Spec.Type == "instant" { + msg := "api error Unsupported: Fleets of type 'instant' cannot be modified." + return nil, ackerr.NewTerminalError(fmt.Errorf("%s", msg)) + } + + // Throw error if an immutable field is updated in the CRD + // The immutableFieldChanges function mentioned in https://aws-controllers-k8s.github.io/community/docs/contributor-docs/code-generator-config/#is_immutable-mutable-vs-immutable-fields does not seem to be working + immutable_fields := []string{"Spec.Type", "Spec.ReplaceUnhealthyInstances", "Spec.TerminateInstancesWithExpiration", "Spec.TargetCapacitySpecification.DefaultTargetCapacityType", "Spec.SpotOptions", "Spec.OnDemandOptions"} + for _, field := range immutable_fields { + if delta.DifferentAt(field) { + // Throw a Terminal Error if immutable fields are modified + msg := "field " + field + " is not updatable after fleet creation" + return nil, ackerr.NewTerminalError(fmt.Errorf("%s", msg)) + } + } + + // This value is automatically populated in TargetCapacitySpecification, but is not supported in ModifyFleetRequest + desired.ko.Spec.TargetCapacitySpecification.DefaultTargetCapacityType = nil + + // Ensure Launch Template Version is int and not $Latest/$Default + // Preventing those values as as those strings are updated in the backend with the ints they represent + // This confuses the reconciliation as the aws state falls out of sync with the CRD + // If we stick to int strings, all works smoothly + for _, config := range desired.ko.Spec.LaunchTemplateConfigs { + if config.LaunchTemplateSpecification != nil { + _, err := strconv.Atoi(*config.LaunchTemplateSpecification.Version) + if err != nil { + msg := "Only int values are supported for Launch Template Version in EC2 fleet spec" + return nil, ackerr.NewTerminalError(fmt.Errorf("%s", msg)) + } + } + } + diff --git a/templates/hooks/fleet/sdk_update_pre_set_output.go.tpl b/templates/hooks/fleet/sdk_update_pre_set_output.go.tpl new file mode 100644 index 00000000..c040cebc --- /dev/null +++ b/templates/hooks/fleet/sdk_update_pre_set_output.go.tpl @@ -0,0 +1,3 @@ + + // Modify Fleet doesn't return an updated Fleet object, so we need to set the state to "modifying" to reflect that the update is in progress + ko.Status.FleetState = aws.String("modifying") diff --git a/test/e2e/bootstrap_resources.py b/test/e2e/bootstrap_resources.py index 138d08cd..d784b2be 100644 --- a/test/e2e/bootstrap_resources.py +++ b/test/e2e/bootstrap_resources.py @@ -20,6 +20,7 @@ from acktest.bootstrapping.vpc import VPC from acktest.bootstrapping.vpc import TransitGateway from acktest.bootstrapping.vpc_endpoint_service import VpcEndpointServiceConfiguration +from acktest.bootstrapping.iam import ServiceLinkedRole from e2e import bootstrap_directory @dataclass @@ -30,6 +31,7 @@ class BootstrapResources(Resources): NetworkLoadBalancer: NetworkLoadBalancer TestTransitGateway: TransitGateway AdoptedVpcEndpointService: VpcEndpointServiceConfiguration + EC2FleetServiceLinkedRole: ServiceLinkedRole _bootstrap_resources = None diff --git a/test/e2e/resources/fleet.yaml b/test/e2e/resources/fleet.yaml new file mode 100644 index 00000000..37de1268 --- /dev/null +++ b/test/e2e/resources/fleet.yaml @@ -0,0 +1,18 @@ +apiVersion: ec2.services.k8s.aws/v1alpha1 +kind: Fleet +metadata: + name: $FLEET_NAME +spec: + targetCapacitySpecification: + totalTargetCapacity: $TOTAL_TARGET_CAPACITY + defaultTargetCapacityType: $DEFAULT_TARGET_CAPACITY_TYPE + launchTemplateConfigs: + - launchTemplateSpecification: + launchTemplateID: $LAUNCH_TEMPLATE_ID + version: $LAUNCH_TEMPLATE_VERSION + overrides: + - subnetID: $SUBNET_ID + type: $FLEET_TYPE + tags: + - key: $FLEET_TAG_KEY + value: $FLEET_TAG_VAL \ No newline at end of file diff --git a/test/e2e/service_bootstrap.py b/test/e2e/service_bootstrap.py index 119b14d7..6929e763 100644 --- a/test/e2e/service_bootstrap.py +++ b/test/e2e/service_bootstrap.py @@ -21,6 +21,7 @@ from acktest.bootstrapping.vpc import TransitGateway from acktest.bootstrapping.vpc_endpoint_service import VpcEndpointServiceConfiguration from acktest.bootstrapping.s3 import Bucket +from acktest.bootstrapping.iam import ServiceLinkedRole from e2e import bootstrap_directory from e2e.bootstrap_resources import BootstrapResources @@ -40,6 +41,12 @@ def service_bootstrap() -> Resources: AdoptedVPC=VPC(name_prefix="e2e-adopted-vpc", num_public_subnet=1, num_private_subnet=0), TestTransitGateway=TransitGateway(), AdoptedVpcEndpointService=VpcEndpointServiceConfiguration(name_prefix="e2e-adopted-vpc-es"), + + EC2FleetServiceLinkedRole=ServiceLinkedRole( + aws_service_name="ec2fleet.amazonaws.com", + default_name="AWSServiceRoleForEC2Fleet", + description="Service-linked role for EC2 Fleet", + ), ) try: diff --git a/test/e2e/tests/helper.py b/test/e2e/tests/helper.py index 54865651..6df3b618 100644 --- a/test/e2e/tests/helper.py +++ b/test/e2e/tests/helper.py @@ -441,3 +441,45 @@ def assert_managed_prefix_list(self, prefix_list_id: str, exists=True): except self.ec2_client.exceptions.ClientError: pass assert res_found is exists + + def get_fleet(self, fleet_id: str) -> Union[None, Dict]: + """Get a fleet by ID.""" + try: + aws_res = self.ec2_client.describe_fleets(FleetIds=[fleet_id]) + if len(aws_res["Fleets"]) > 0: + fleet_list = aws_res["Fleets"][0] + return fleet_list + return None + except self.ec2_client.exceptions.ClientError: + return None + + def wait_fleet_state(self, fleet_id: str, expected_state: str, max_wait_seconds: int = 120) -> bool: + """Wait for a fleet to reach the expected state. + + Args: + fleet_id: The ID of the fleet to wait for + expected_state: The expected state (e.g., 'submitted', 'active') + max_wait_seconds: Maximum time to wait in seconds + + Returns: + True if the expected state was reached, False otherwise + """ + interval = 5 + max_tries = max_wait_seconds // interval + + for tries in range(max_tries): + fleet = self.get_fleet(fleet_id) + if fleet is None: + return False + + current_state = fleet.get('FleetState', '') + if current_state == expected_state: + return True + + # Check if we're in an error state + if 'failed' in current_state.lower(): + return False + + time.sleep(interval) + + return False diff --git a/test/e2e/tests/test_fleet.py b/test/e2e/tests/test_fleet.py new file mode 100644 index 00000000..a435082b --- /dev/null +++ b/test/e2e/tests/test_fleet.py @@ -0,0 +1,459 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You may +# not use this file except in compliance with the License. A copy of the +# License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. + +"""Integration tests for Managed Prefix List API. +""" + +import pytest +import time +import logging +import boto3 + +from acktest import tags +from acktest.resources import random_suffix_name +from acktest.k8s import resource as k8s +from e2e import service_marker, CRD_GROUP, CRD_VERSION, load_ec2_resource +from e2e.bootstrap_resources import get_bootstrap_resources +from e2e.replacement_values import REPLACEMENT_VALUES +from e2e.tests.helper import EC2Validator + +RESOURCE_PLURAL = "fleets" + +CREATE_WAIT_AFTER_SECONDS = 10 +UPDATE_WAIT_AFTER_SECONDS = 10 +DELETE_WAIT_AFTER_SECONDS = 10 + +FLEET_TAG_KEY = "owner" +FLEET_TAG_VAL = "ack-controller" + +def get_ami_id(ec2_client): + try: + # Use latest AL2023 + resp = ec2_client.describe_images( + Owners=['amazon'], + Filters=[ + {"Name": "architecture", "Values": ['x86_64']}, + {"Name": "state", "Values": ['available']}, + {"Name": "virtualization-type", "Values": ['hvm']}, + ], + ) + for image in resp['Images']: + if 'Description' in image: + if "Amazon Linux 2023" in image['Description']: + return image['ImageId'] + except Exception as e: + logging.debug(e) + + +@pytest.fixture(scope="module") +def ec2_validator(): + """Fixture to provide EC2 validator for AWS API calls.""" + ec2_client = boto3.client("ec2") + return EC2Validator(ec2_client) + +@pytest.fixture +def standard_launch_template(ec2_client): + resource_name = random_suffix_name("lt-ack-test", 24) + resource_file = "launch_template" + + replacements = REPLACEMENT_VALUES.copy() + replacements["LAUNCH_TEMPLATE_NAME"] = resource_name + + # Load LaunchTemplate CR + resource_data = load_ec2_resource( + resource_file, + additional_replacements=replacements, + ) + ami_id = get_ami_id(ec2_client) + resource_data["spec"]["data"]["imageID"] = ami_id + resource_data["spec"]["data"]["instanceType"] = 't3.nano' + + # Create k8s resource + ref = k8s.CustomResourceReference( + CRD_GROUP, CRD_VERSION, "launchtemplates", + resource_name, namespace="default", + ) + k8s.create_custom_resource(ref, resource_data) + time.sleep(CREATE_WAIT_AFTER_SECONDS) + + cr = k8s.wait_resource_consumed_by_controller(ref) + assert cr is not None + assert k8s.get_resource_exists(ref) + + yield (ref, cr) + + # Teardown + try: + _, deleted = k8s.delete_custom_resource(ref, 3, 10) + assert deleted + except: + pass + +@pytest.fixture +def simple_fleet(standard_launch_template, request): + resource_name = random_suffix_name("fleet", 32) + + (_, launch_template) = standard_launch_template + + subnet_id = get_bootstrap_resources().SharedTestVPC.public_subnets.subnet_ids[0] + launch_template_id = launch_template["status"]["id"] + + test_resource_values = REPLACEMENT_VALUES.copy() + test_resource_values["FLEET_NAME"] = resource_name + test_resource_values["TOTAL_TARGET_CAPACITY"] = "1" + test_resource_values["DEFAULT_TARGET_CAPACITY_TYPE"] = "spot" + test_resource_values["LAUNCH_TEMPLATE_ID"] = launch_template_id + test_resource_values["LAUNCH_TEMPLATE_VERSION"] = "'1'" + test_resource_values["FLEET_TAG_KEY"] = FLEET_TAG_KEY + test_resource_values["FLEET_TAG_VAL"] = FLEET_TAG_VAL + test_resource_values["SUBNET_ID"] = subnet_id + + marker = request.node.get_closest_marker("resource_data") + if marker is not None: + data = marker.args[0] + if 'fleet_type' in data: + test_resource_values["FLEET_TYPE"] = data['fleet_type'] + + # Load the resource + resource_data = load_ec2_resource( + "fleet", + additional_replacements=test_resource_values, + ) + + # Create k8s resource + ref = k8s.CustomResourceReference( + CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, + resource_name, namespace="default", + ) + k8s.create_custom_resource(ref, resource_data) + time.sleep(CREATE_WAIT_AFTER_SECONDS) + + cr = k8s.wait_resource_consumed_by_controller(ref) + assert cr is not None + assert k8s.get_resource_exists(ref) + + yield (ref, cr) + + # Teardown + try: + _, deleted = k8s.delete_custom_resource(ref, 3, 10) + assert deleted + except: + pass + +@service_marker +@pytest.mark.canary +class TestFleets: + @pytest.mark.resource_data({'fleet_type': 'instant'}) + def test_crud_instant(self, simple_fleet, ec2_validator): + """ + Test creation, update and deletion of an Fleet of type instant. + Fleets of type instant do not support fleet updates, so this test verifies tag updates, and verifies that other update types are blocked and result in terminal conditions. + """ + (ref, cr) = simple_fleet + + resource = k8s.get_resource(ref) + fleet_id = cr["status"]["fleetID"] + + time.sleep(CREATE_WAIT_AFTER_SECONDS) + assert k8s.wait_on_condition(ref, "ACK.ResourceSynced", "True", wait_periods=5) + + # Check Fleet exists + fleet = ec2_validator.get_fleet(fleet_id) + assert fleet is not None + + # Check system and user tags exist for fleet resource + user_tags = { + FLEET_TAG_KEY: FLEET_TAG_VAL + } + tags.assert_ack_system_tags( + tags=fleet["Tags"], + ) + tags.assert_equal_without_ack_tags( + expected=user_tags, + actual=fleet["Tags"], + ) + + # Only user tags should be present in Spec + assert len(resource["spec"]["tags"]) == 1 + assert resource["spec"]["tags"][0]["key"] == FLEET_TAG_KEY + assert resource["spec"]["tags"][0]["value"] == FLEET_TAG_VAL + + # Update tags + update_tags = [ + { + "key": "updatedtagkey", + "value": "updatedtagvalue", + } + ] + + # Patch the Fleet, updating the tags with new pair + updates = { + "spec": {"tags": update_tags}, + } + + k8s.patch_custom_resource(ref, updates) + time.sleep(UPDATE_WAIT_AFTER_SECONDS) + + # Check resource synced successfully + assert k8s.wait_on_condition(ref, "ACK.ResourceSynced", "True", wait_periods=5) + + # Check for updated user tags; system tags should persist + fleet = ec2_validator.get_fleet(fleet_id) + updated_tags = { + "updatedtagkey": "updatedtagvalue" + } + tags.assert_ack_system_tags( + tags=fleet["Tags"], + ) + tags.assert_equal_without_ack_tags( + expected=updated_tags, + actual=fleet["Tags"], + ) + + # Only user tags should be present in Spec + resource = k8s.get_resource(ref) + assert len(resource["spec"]["tags"]) == 1 + assert resource["spec"]["tags"][0]["key"] == "updatedtagkey" + assert resource["spec"]["tags"][0]["value"] == "updatedtagvalue" + + # Patch the fleet resource, deleting the tags + updates = { + "spec": {"tags": []}, + } + + k8s.patch_custom_resource(ref, updates) + time.sleep(UPDATE_WAIT_AFTER_SECONDS) + + # Check resource synced successfully + assert k8s.wait_on_condition(ref, "ACK.ResourceSynced", "True", wait_periods=5) + + # Check for removed user tags; system tags should persist + fleet = ec2_validator.get_fleet(fleet_id) + tags.assert_ack_system_tags( + tags=fleet["Tags"], + ) + tags.assert_equal_without_ack_tags( + expected=[], + actual=fleet["Tags"], + ) + + # Check user tags are removed from Spec + resource = k8s.get_resource(ref) + assert len(resource["spec"]["tags"]) == 0 + + # Attempt to Update Fleet Target Capacity + # This will fail as fleets of type instant cannot be modified after creation + initialFleetTargetCapacity = fleet['TargetCapacitySpecification']['TotalTargetCapacity'] + updatedFleetTargetCapacity = 2 + updates = { + "spec": { + "targetCapacitySpecification": { + "totalTargetCapacity": updatedFleetTargetCapacity, + "spotTargetCapacity": updatedFleetTargetCapacity + } + } + } + k8s.patch_custom_resource(ref, updates) + time.sleep(UPDATE_WAIT_AFTER_SECONDS) + + # Check resource synced successfully + assert k8s.wait_on_condition(ref, "ACK.Terminal", "True", wait_periods=5) + + # Check Fleet updated value + fleet = ec2_validator.get_fleet(fleet_id) + assert fleet is not None + assert fleet['TargetCapacitySpecification']['TotalTargetCapacity'] == initialFleetTargetCapacity + + # Delete k8s resource + _, deleted = k8s.delete_custom_resource(ref) + assert deleted is True + + time.sleep(DELETE_WAIT_AFTER_SECONDS) + + # Wait for AWS to start deleting resource, which can take a few minutes so no need to wait for deletion to complete + ec2_validator.wait_fleet_state( + fleet_id, + 'deleted_terminating', + max_wait_seconds=180 + ) + + @pytest.mark.resource_data({'fleet_type': 'maintain'}) + def test_crud_maintain(self, simple_fleet, ec2_validator): + """ + Test creation, update and deletion of an Fleet of type maintain. + """ + (ref, cr) = simple_fleet + + time.sleep(CREATE_WAIT_AFTER_SECONDS) + + # Check that the resource was created + assert cr is not None + assert 'status' in cr + assert 'fleetID' in cr['status'] + + fleet_id = cr['status']['fleetID'] + assert fleet_id is not None + + # Check Fleet exists + fleet = ec2_validator.get_fleet(fleet_id) + assert fleet is not None + + # Wait for AWS to complete creation + state_reached = ec2_validator.wait_fleet_state( + fleet_id, + 'active', + max_wait_seconds=180 + ) + assert state_reached, f"Fleet {fleet_id} did not reach active state within timeout" + + # Wait for K8s controller to sync the state from AWS + assert k8s.wait_on_condition(ref, "ACK.ResourceSynced", "True", wait_periods=30), \ + "Resource did not sync within timeout" + + # Verify state + cr = k8s.get_resource(ref) + assert cr['status'].get('fleetState') == 'active', \ + f"Expected fleetState active, got {cr['status'].get('fleetState')}" + + + # Update Fleet Target Capacity + updatedFleetTargetCapacity = 2 + updates = { + "spec": { + "targetCapacitySpecification": { + "totalTargetCapacity": updatedFleetTargetCapacity, + "spotTargetCapacity": updatedFleetTargetCapacity + } + } + } + k8s.patch_custom_resource(ref, updates) + time.sleep(UPDATE_WAIT_AFTER_SECONDS) + + # Check resource synced successfully + assert k8s.wait_on_condition(ref, "ACK.ResourceSynced", "True", wait_periods=10) + + # Check Fleet updated value + fleet = ec2_validator.get_fleet(fleet_id) + assert fleet is not None + assert fleet['TargetCapacitySpecification']['TotalTargetCapacity'] == updatedFleetTargetCapacity + + # Delete k8s resource + _, deleted = k8s.delete_custom_resource(ref, 2, 5) + assert deleted is True + + # Wait for AWS to start deleting resource, which can take a few minutes so no need to wait for deletion to complete + ec2_validator.wait_fleet_state( + fleet_id, + 'deleted_terminating', + max_wait_seconds=180 + ) + + + @pytest.mark.resource_data({'fleet_type': 'maintain'}) + def test_crud_immutable_fields(self, simple_fleet, ec2_validator): + """ + Spin up a maintain Fleet and attempt to update immutable fields on the Fleet, + Validate that these updates are blocked and result in terminal conditions, and that the AWS resource is not updated with the invalid values. + """ + (ref, cr) = simple_fleet + + time.sleep(CREATE_WAIT_AFTER_SECONDS) + + # Check that the resource was created + assert cr is not None + assert 'status' in cr + assert 'fleetID' in cr['status'] + + fleet_id = cr['status']['fleetID'] + assert fleet_id is not None + assert fleet_id.startswith('fleet-') + + # Check Fleet exists + fleet = ec2_validator.get_fleet(fleet_id) + assert fleet is not None + + # Wait for AWS to complete creation + state_reached = ec2_validator.wait_fleet_state( + fleet_id, + 'active', + max_wait_seconds=180 + ) + assert state_reached, f"Fleet {fleet_id} did not reach active state within timeout" + + # Wait for K8s controller to sync the state from AWS + assert k8s.wait_on_condition(ref, "ACK.ResourceSynced", "True", wait_periods=30), \ + "Resource did not sync within timeout" + + # Update Fleet Default Capacity Specification + # updates on this field are not supported, so this should not result in any updates on AWS resource + initialDefaultTargetCapacityType = fleet['TargetCapacitySpecification']['DefaultTargetCapacityType'] + updatedDefaultTargetCapacityType = "on-demand" + updates = { + "spec": { + "targetCapacitySpecification": { + "defaultTargetCapacityType": updatedDefaultTargetCapacityType, + } + } + } + k8s.patch_custom_resource(ref, updates) + + # Check resource prevents this invalid update and enters terminal state + assert k8s.wait_on_condition(ref, "ACK.Terminal", "True", wait_periods=10) + + # Check fleet value has not been updated on AWS + fleet = ec2_validator.get_fleet(fleet_id) + assert fleet is not None + assert fleet['TargetCapacitySpecification']['DefaultTargetCapacityType'] == initialDefaultTargetCapacityType + + # Update Fleet Default Capacity Specification back to original value + updates = { + "spec": { + "targetCapacitySpecification": { + "defaultTargetCapacityType": initialDefaultTargetCapacityType, + } + } + } + k8s.patch_custom_resource(ref, updates) + # Check resource prevents this invalid update and enters terminal state + assert k8s.wait_on_condition(ref, "ACK.ResourceSynced", "True", wait_periods=10) + + # Update Fleet ReplaceUnhealthyInstances + # updates on this field are not supported, so this should not result in any updates on AWS resource + initialReplaceUnhealthyInstances = fleet['ReplaceUnhealthyInstances'] + updatedReplaceUnhealthyInstances = not fleet['ReplaceUnhealthyInstances'] + updates = { + "spec": { + "replaceUnhealthyInstances": updatedReplaceUnhealthyInstances, + } + } + k8s.patch_custom_resource(ref, updates) + + # Check resource prevents this invalid update and enters terminal state + assert k8s.wait_on_condition(ref, "ACK.Terminal", "True", wait_periods=10) + + # Check fleet value has not been updated on AWS + fleet = ec2_validator.get_fleet(fleet_id) + assert fleet is not None + assert fleet['ReplaceUnhealthyInstances'] == initialReplaceUnhealthyInstances + + # Delete k8s resource + _, deleted = k8s.delete_custom_resource(ref, 2, 5) + assert deleted is True + + # Wait for AWS to start deleting resource, which can take a few minutes so no need to wait for deletion to complete + ec2_validator.wait_fleet_state( + fleet_id, + 'deleted_terminating', + max_wait_seconds=180 + ) \ No newline at end of file