├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── components ├── config │ ├── base_config.yaml │ ├── config.go │ ├── config_test.go │ └── default_config.go ├── converter_logic │ ├── block_converter_logic.go │ ├── converter_logic.go │ ├── converter_logic_test.go │ ├── default_converter_logic.go │ ├── joined_converter_logic.go │ └── map_converter_logic.go ├── debug │ └── debug.go ├── document_leaf │ └── document_leaf.go ├── encoding │ ├── encoding.go │ └── encoding_test.go ├── input_source │ ├── helm_input_source.go │ ├── input_source.go │ └── stdin_input_source.go ├── leaf │ └── leaf.go ├── map_utils │ └── sort_keys.go ├── output_target │ ├── directory_output_target.go │ ├── output_target.go │ ├── stdout_output_target.go │ └── unit_path.go ├── parsed_leaf │ └── parsed_leaf.go ├── policy │ ├── policy.go │ └── template_policy.go ├── policy_path │ ├── policy_path.go │ └── policy_path_test.go ├── policy_set │ ├── basic_policy_set.go │ └── policy_set.go ├── template │ ├── template.go │ └── template_test.go ├── template_function_map │ └── create_function_map.go └── terraform_format │ ├── escape_non_tf_vars.go │ ├── format_key.go │ ├── format_resource_name.go │ ├── format_string_value.go │ ├── indent.go │ ├── quote.go │ ├── snake_case.go │ ├── strip_vars.go │ └── terraform_format_test.go ├── go.mod ├── go.sum ├── main.go └── release /.gitignore: -------------------------------------------------------------------------------- 1 | dredger 2 | build/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | prefix=/usr/local 2 | 3 | dredger: main.go components/*/*.go components/config/base_config.yaml 4 | go build -o $@ $< 5 | 6 | install: dredger 7 | install dredger $(prefix)/bin/ 8 | 9 | test: 10 | go test -covermode=count "./components/..." 11 | 12 | clean: 13 | rm -f dredger 14 | 15 | .PHONY=test clean 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dredger 2 | 3 | Dredger is a utility to help convert helm charts to Terraform modules using kubernetes provider. 4 | 5 | Dredger is made of dark magic and cannot fully convert a helm chart. It is designed to perform the bulk of the work but will still require some knowledge of Terraform HCL. 6 | 7 | ## quick start 8 | ``` 9 | # Run dredger against the bitnami helm chart and write module to /tmp/dredger-redis 10 | dredger --outputdir /tmp/dredger-redis helm --repo https://charts.bitnami.com/bitnami redis-cluster --set networkPolicy.enabled=true 11 | 12 | # Now create the terraform to consume this module 13 | 14 | mkdir /tmp/dredger-main 15 | cd /tmp/dredger-main 16 | 17 | cat > main.tf < /tmp/custom_dredger_config.yaml 72 | ``` 73 | Then edit the output file makeing any alterations you require. Details on how the configuration works can be found at the top of the dumped config. 74 | 75 | When you want to execute dredger with this config use the flag `--config` to specify the path to your custom file. 76 | ``` 77 | dredger --config /tmp/custom_dredger_config.yaml helm bar/foo 78 | ``` 79 | -------------------------------------------------------------------------------- /components/config/base_config.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021 Synchronoss Technologies 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | ############################################################################### 16 | # Templates # 17 | ############################################################################### 18 | # 19 | # These are in-built templates defined here for re-usability. 20 | # 21 | # Dredger supplies leaf data in the following variables: 22 | # 23 | # Value: The value at the current leaf in the structure. 24 | # Key: The last key that we iterated into. 25 | # Trail: A string listing the keys down to this value, dot delimited. 26 | # e.g. "foo.bar.baz" 27 | # Sub: Substitute value that would have been inserted without this policy. 28 | # SubValue: The substitue value before joining with the current logic 29 | # Doc: The top level structure 30 | # 31 | # So given the following structure: 32 | # 33 | # { 34 | # "fuzz": { 35 | # "foo": ["bar", "baz"] 36 | # } 37 | # } 38 | # 39 | # The policy path: "fuzz.foo", would be presented the values: 40 | # 41 | # Value: ['bar', 'baz'] 42 | # Key: 'foo' 43 | # Trail: 'fuzz.foo' 44 | # Sub: 'foo = ["bar", "baz"]' 45 | # SubValue: ['"bar"', '"baz"'] 46 | # Doc: "fuzz": { "foo":["bar", "baz"] } 47 | # 48 | 49 | templates: 50 | 51 | # ignoreKey 52 | # 53 | # Just ingore the key 54 | # 55 | ignoreKey: &ignoreKey "" 56 | 57 | # singularizeArray 58 | # 59 | # By default dredger will map format any arrays that it 60 | # encounters. This template strips the 's' from the end of 61 | # the key and repeats the key for each member of the array 62 | # 63 | singularizeArray: &singularizeArray | 64 | {{ $singleKey := regexReplaceAll "s$" $.Key "" }} 65 | {{ range $i, $v := $.SubValue }} 66 | {{ $singleKey }}{{ $v }} 67 | {{ end }} 68 | 69 | # unwindArray 70 | # 71 | # By default dredger will map format any arrays that it 72 | # encounters. This template repeats the last key for each 73 | # member of the array 74 | # 75 | unwindArray: &unwindArray | 76 | {{ range $i, $v := $.SubValue }} 77 | {{ $.Key }}{{ $v }} 78 | {{ end }} 79 | 80 | # scopedVariable 81 | # 82 | # replace the value with a variable scoped to the k8s 83 | # resource 84 | # 85 | scopedVariable: &scopedVariable | 86 | {{ $name := $.Doc.metadata.name | stripTfVars }} 87 | {{ $.Key }} = var.{{ $name }}-{{ $.Key }} 88 | 89 | # setMap 90 | # 91 | # Set the subtree to map format 92 | setMap: &setMap | 93 | {{ toTfMap $.Value $.Key }} 94 | 95 | # scopedVariableUnit 96 | # 97 | # Creates a scoped Variable unit defining the input for a 98 | # variable emplacement. 99 | scopedVariableUnit: &scopedVariableUnit | 100 | {{- $name := $.Doc.metadata.name | stripTfVars }} 101 | variable "{{ $name }}-{{ $.Key }}" { 102 | {{- if kindIs "int" $.Value }} 103 | type = number 104 | {{- else if kindIs "string" $.Value }} 105 | type = string 106 | {{- else if kindIs "bool" $.Value }} 107 | type = bool 108 | {{- end }} 109 | default = {{ $.Value }} 110 | } 111 | 112 | setOctal: &setOctal | 113 | {{ $.Key }} = "{{ toOctal $.Value }}" # Set as octal 114 | 115 | ############################################################################### 116 | # Policies # 117 | ############################################################################### 118 | # 119 | # This is the main structure that Dredger reads and enacts. 120 | # 121 | # Each policy consists of a path in the document where the 122 | # injection takes place and a template to render the new entry. 123 | # 124 | # Optionally a unit_template can be specified to render an 125 | # entirely new resource outside of the parsing structure. This 126 | # is useful for defining variables or outputs based on the data 127 | # found in the document. 128 | # 129 | 130 | policies: 131 | 132 | # resourceKubernetes 133 | # 134 | # The top level policy converts the document into a resource 135 | # 136 | # NOTE: For some stupid reason DaemonSets are named wrong 137 | - path: "" 138 | template: | 139 | {{- $name := formatResourceName $.Doc.metadata.name }} 140 | {{- $kind := snakecase $.Doc.kind }} 141 | 142 | {{- if eq $.Doc.kind "ServiceMonitor" }} 143 | resource "kubernetes_manifest" "{{$kind}}_{{$name}}" { 144 | provider = kubernetes-alpha 145 | {{ toTfMap $.Value "manifest" }} 146 | } 147 | {{- else}} 148 | {{- if eq $.Doc.kind "DaemonSet" }} 149 | resource "kubernetes_daemonset" "{{ $name }}" { 150 | {{- else }} 151 | resource "kubernetes_{{ $kind }}" "{{ $name }}" { 152 | {{- end }} 153 | {{- range $k, $v := $.SubValue }} 154 | {{- $v | nindent 2 }} 155 | {{- end }} 156 | } 157 | {{- end}} 158 | 159 | # Some charts have an annoying habit of not including the 160 | # namespace in the metadata 161 | - path: "metadata" 162 | template: | 163 | {{- if $.SubValue.namespace }} 164 | {{ $.Sub }} 165 | {{- else if hasPrefix "Cluster" $.Doc.kind }} 166 | {{ $.Sub }} 167 | {{- else }} 168 | metadata { 169 | namespace = var.namespace 170 | {{- range $k, $v := $.SubValue }} 171 | {{- $v | nindent 2 }} 172 | {{- end }} 173 | } 174 | {{- end }} 175 | 176 | # labelsAreMap 177 | # 178 | # labels are always maps 179 | - path: "metadata.labels" 180 | template: *setMap 181 | 182 | - path: "spec.**.metadata.labels" 183 | template: *setMap 184 | 185 | - path: "spec.**.matchLabels" 186 | template: *setMap 187 | 188 | - path: "spec.volumeClaimTemplates.*.spec.resources.requests" 189 | template: *setMap 190 | 191 | # annotations are maps 192 | - path: "metadata.annotations" 193 | template: *setMap 194 | 195 | - path: "spec.**.metadata.annotations" 196 | template: *setMap 197 | 198 | # PersistentVolumeClaims requests it's size with a map 199 | - path: "spec.resources.requests" 200 | template: *setMap 201 | 202 | # nodeSelector is a map 203 | - path: "spec.template.spec.nodeSelector" 204 | template: *setMap 205 | 206 | # Service selectors are maps, but not deployable selectors 207 | - path: "spec.selector" 208 | template: | 209 | {{- if eq $.Doc.kind "Service" }} 210 | {{- toTfMap $.Value $.Key }} 211 | {{- else }} 212 | {{- $.Sub }} 213 | {{- end }} 214 | 215 | # replicasVariable 216 | # 217 | # Set the replicas as a variable in all instances. 218 | # 219 | # Also creates a unit for the varible decleration with the 220 | # default set to the document value 221 | # 222 | - path: "spec.replicas" 223 | template: *scopedVariable 224 | unit_template: 225 | - *scopedVariableUnit 226 | 227 | # singularize serviceAccount secrets 228 | - path: "secrets" 229 | template: *singularizeArray 230 | 231 | # unwind deployable container env_from 232 | - path: "spec.template.spec.containers.*.envFrom" 233 | template: *unwindArray 234 | 235 | - path: "spec.template.spec.initContainers.*.envFrom" 236 | template: *unwindArray 237 | 238 | # unwind whatever this is 239 | - path: "spec.**.preferredDuringSchedulingIgnoredDuringExecution" 240 | template: *unwindArray 241 | - path: "spec.**.requiredDuringSchedulingIgnoredDuringExecution" 242 | template: *unwindArray 243 | 244 | 245 | # singularize deployable containers 246 | - path: "spec.**.containers" 247 | template: *singularizeArray 248 | 249 | # singularize deployable containers volumeMounts 250 | - path: "spec.**.containers.*.volumeMounts" 251 | template: *singularizeArray 252 | - path: "spec.**.initContainers.*.volumeMounts" 253 | template: *singularizeArray 254 | 255 | # singularize deployable container ports 256 | - path: "spec.**.containers.*.ports" 257 | template: *singularizeArray 258 | - path: "spec.**.initContainers.*.ports" 259 | template: *singularizeArray 260 | 261 | # singularize service ports 262 | - path: "spec.ports" 263 | template: *singularizeArray 264 | 265 | # singularize probe http_get http_headers 266 | - path: "spec.template.spec.containers.*.*.httpGet.httpHeaders" 267 | template: *singularizeArray 268 | 269 | # singularize mutating webhooks containers 270 | - path: "webhooks" 271 | template: *singularizeArray 272 | 273 | 274 | # unwind deployable container env entries 275 | - path: "spec.**.containers.*.env" 276 | template: *unwindArray 277 | - path: "spec.**.initContainers.*.env" 278 | template: *unwindArray 279 | 280 | # unwind deployable volumes items 281 | - path: "spec.**.volumes.*.*.items" 282 | template: *unwindArray 283 | 284 | # unwind volume projected sources 285 | - path: "spec.**.volumes.*.projected.sources" 286 | template: *unwindArray 287 | 288 | # singularize tolerations 289 | - path: "spec.**.tolerations" 290 | template: *singularizeArray 291 | 292 | # singularize deployable volumeClaimTemplates 293 | - path: "spec.volumeClaimTemplates" 294 | template: *singularizeArray 295 | 296 | # singularize initContainers 297 | - path: "spec.**.initContainers" 298 | template: *singularizeArray 299 | 300 | # singularize deployable volumes but not for securitypolicies 301 | - path: "spec.**.volumes" 302 | template: | 303 | {{ if eq "PodSecurityPolicy" $.Doc.kind }} 304 | {{ $.Sub }} 305 | {{ else }} 306 | {{ $singleKey := regexReplaceAll "s$" $.Key "" }} 307 | {{ range $i, $v := $.SubValue }} 308 | {{ $singleKey }}{{ $v }} 309 | {{ end }} 310 | {{ end }} 311 | 312 | 313 | # singularize deployable volumeClaimTemplates 314 | - path: "rules" 315 | template: *singularizeArray 316 | 317 | # singularize *_role_binding subjects 318 | - path: "subjects" 319 | template: *singularizeArray 320 | 321 | 322 | # unwind networkpolicy ingress and egress 323 | - path: "spec.ingress" 324 | template: *unwindArray 325 | - path: "spec.egress" 326 | template: *unwindArray 327 | 328 | # unwind networpolicy *gress ports 329 | - path: "spec.egress.*.ports" 330 | template: *unwindArray 331 | - path: "spec.ingress.*.ports" 332 | template: *unwindArray 333 | 334 | # unwind networpolicy *gress "to" 335 | - path: "spec.egress.*.to" 336 | template: *unwindArray 337 | - path: "spec.ingress.*.to" 338 | template: *unwindArray 339 | 340 | # Terraform doens't need kind as a key 341 | - path: "kind" 342 | template: *ignoreKey 343 | 344 | # Terraform doens't need to know the apiVersion 345 | - path: "apiVersion" 346 | template: *ignoreKey 347 | 348 | # Terraform kubernetes provider doesn't recognise sysctls 349 | - path: "spec.template.spec.securityContext.sysctls" 350 | template: *ignoreKey 351 | 352 | # Set the defaultMode of any volumes mounts as octal 353 | # which terraform understands as a 0 prefixed string 354 | - path: "spec.template.spec.volumes.*.*.defaultMode" 355 | template: *setOctal 356 | 357 | # Deployable resources are set as a variable in the 358 | # format $name-resources. The default for this variable 359 | # will be the 360 | - path: "spec.template.spec.containers.*.resources" 361 | template: | 362 | {{- $name := $.Doc.metadata.name | stripTfVars }} 363 | resources { 364 | limits = var.{{ $name }}-resources.limits 365 | requests = var.{{ $name }}-resources.requests 366 | } 367 | unit_template: 368 | - | 369 | {{- $name := $.Doc.metadata.name | stripTfVars }} 370 | variable "{{ $name }}-resources" { 371 | type = object({ requests = map(string), limits = map(string) }) 372 | {{ if eq 2 (len (keys $.Value)) }} 373 | # using in-built default 374 | {{ toTfMap $.Value "default" | nindent 2 }} 375 | {{ else }} 376 | # using dredger default 377 | default = { requests = null, limits = null } 378 | {{ end }} 379 | } 380 | 381 | # Resources in init containers are ignored as they are often added 382 | # accidentaly 383 | - path: "spec.template.spec.initContainers.*.resources" 384 | template: *ignoreKey 385 | 386 | # With Secret.data we defined a single variable then add each 387 | # key as an object property within that variable 388 | # 389 | # But with ConfigMap.data we just call toTfMap 390 | - path: "data" 391 | template: | 392 | {{- if eq $.Doc.kind "Secret" }} 393 | {{- $name := stripTfVars $.Doc.metadata.name }} 394 | data = { 395 | {{- range $k, $v := $.Value }} 396 | {{ $k | quote }} = var.{{ $name }}-secrets.{{ $k }} 397 | {{- end }} 398 | } 399 | {{- else }} 400 | {{- toTfMap $.Value "data" }} 401 | {{- end }} 402 | unit_template: 403 | - | 404 | {{- if eq $.Doc.kind "Secret" }} 405 | {{- $name := stripTfVars $.Doc.metadata.name }} 406 | variable "{{ $name }}-secrets" { 407 | sensitive = true 408 | type = object({ 409 | {{- range $k, $v := $.Value }} 410 | {{ $k }} = string 411 | {{- end }} 412 | }) 413 | } 414 | {{- end }} 415 | 416 | ############################################################################### 417 | # Static units # 418 | ############################################################################### 419 | # 420 | # Static units are a way of adding "global" units. They are added as text once 421 | # per execution of dredger. 422 | # 423 | # These are useful if you have a unit that always needs to be added. 424 | # 425 | # Static units are plain strings not templates 426 | # 427 | 428 | static_units: 429 | - | 430 | variable "name" { 431 | type = string 432 | } 433 | - | 434 | variable "namespace" { 435 | type = string 436 | } 437 | -------------------------------------------------------------------------------- /components/config/config.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package config 17 | 18 | // 19 | // Here the basic config structure is defined along with 20 | // the function to unmarshal it from yaml 21 | 22 | import ( 23 | "gopkg.in/yaml.v3" 24 | "io/ioutil" 25 | ) 26 | 27 | type Config struct { 28 | StaticUnits []string `yaml:"static_units"` 29 | Policies []PolicyConfig `yaml:"policies"` 30 | } 31 | 32 | type PolicyConfig struct { 33 | Path string `yaml:"path"` 34 | Template string `yaml:"template"` 35 | UnitTemplate []string `yaml:"unit_template"` 36 | } 37 | 38 | func LoadConfig(configFile string) (*Config, error) { 39 | if configFile == "" { 40 | return loadDefaultConfig() 41 | } else { 42 | return loadConfigPath(configFile) 43 | } 44 | } 45 | 46 | func loadDefaultConfig() (*Config, error) { 47 | return unmarshalConfig(baseConfig) 48 | } 49 | 50 | func unmarshalConfig(configStr string) (*Config, error) { 51 | config := Config{} 52 | yamlErr := yaml.Unmarshal([]byte(configStr), &config) 53 | 54 | return &config, yamlErr 55 | } 56 | 57 | func loadConfigPath(configFile string) (*Config, error) { 58 | bytes, err := ioutil.ReadFile(configFile) 59 | 60 | if err != nil { 61 | return nil, err 62 | } 63 | 64 | return unmarshalConfig(string(bytes)) 65 | } 66 | -------------------------------------------------------------------------------- /components/config/config_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package config 17 | 18 | import ( 19 | "testing" 20 | ) 21 | 22 | func TestConfig(t *testing.T) { 23 | baseConfig := LoadDefaultConfig() 24 | 25 | if baseConfig == "" { 26 | t.Fatalf("LoadDefaultConfig returned empty") 27 | } 28 | 29 | c, err := unmarshalConfig(baseConfig) 30 | 31 | if err != nil { 32 | t.Fatal(err) 33 | } 34 | 35 | if c == nil { 36 | t.Fatalf("Unmarshaled config is nil") 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /components/config/default_config.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package config 17 | 18 | import _ "embed" 19 | 20 | //go:embed base_config.yaml 21 | var baseConfig string 22 | 23 | // Litterally just returns the base config 24 | 25 | func LoadDefaultConfig() string { 26 | return baseConfig 27 | } 28 | -------------------------------------------------------------------------------- /components/converter_logic/block_converter_logic.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package converter_logic 17 | 18 | import ( 19 | "fmt" 20 | "github.com/synchronoss/dredger/components/map_utils" 21 | "github.com/synchronoss/dredger/components/terraform_format" 22 | ) 23 | 24 | // 25 | // converter logic for terraform "block" format e.g. 26 | // 27 | // section { 28 | // key = "value" 29 | // foo { 30 | // bar = 22 31 | // } 32 | // foo { 33 | // baz = 420 34 | // } 35 | // } 36 | // 37 | 38 | type blockConverterLogic struct{} 39 | 40 | func (dl blockConverterLogic) FormatKey(k string) string { 41 | return terraform_format.SnakeCase(k) 42 | } 43 | 44 | func (dl blockConverterLogic) FormatMap(k string, m map[string]string) string { 45 | 46 | var content = "" 47 | 48 | // Iterate through the keys in sorted order (for consistency) 49 | for _, k := range map_utils.SortKeysString(m) { 50 | 51 | // The sub-value already contains the key so just append 52 | // to the content with a newline. 53 | content += m[k] + "\n" 54 | } 55 | 56 | // Indent the whole content. 57 | indentContent := terraform_format.Indent(content) 58 | 59 | // Build the braced leaf-string 60 | return fmt.Sprintf("%s {\n%s\n}", k, indentContent) 61 | } 62 | 63 | func (dl blockConverterLogic) FormatArray(k string, a []string) string { 64 | var content = "" 65 | 66 | for _, v := range a { 67 | content += v + "\n" 68 | } 69 | 70 | return content 71 | } 72 | 73 | func (dl blockConverterLogic) FormatString(k string, v string) string { 74 | key := terraform_format.AssignKey(k) 75 | s := terraform_format.FormatStringValue(v) 76 | return fmt.Sprintf("%s %s", key, s) 77 | } 78 | 79 | func (dl blockConverterLogic) FormatInt(k string, v int) string { 80 | key := terraform_format.AssignKey(k) 81 | return fmt.Sprintf("%s %d", key, v) 82 | } 83 | 84 | func (dl blockConverterLogic) FormatFloat(k string, v float64) string { 85 | key := terraform_format.AssignKey(k) 86 | return fmt.Sprintf("%s %f", key, v) 87 | } 88 | 89 | func (dl blockConverterLogic) FormatBool(k string, v bool) string { 90 | key := terraform_format.AssignKey(k) 91 | return fmt.Sprintf("%s %t", key, v) 92 | } 93 | 94 | func (dl blockConverterLogic) FormatNill(k string) string { 95 | return "" 96 | } 97 | 98 | func CreateBlockConverterLogic() ConverterLogic { 99 | return blockConverterLogic{} 100 | } 101 | -------------------------------------------------------------------------------- /components/converter_logic/converter_logic.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package converter_logic 17 | 18 | // 19 | // An interface for the converter logic. 20 | // 21 | // converter logic classes must specify what to do for each encountered 22 | // base type. 23 | // 24 | // These functions act upon branches where the sub-branches have already 25 | // been converted, so each container member has a string sub-type. 26 | 27 | type ConverterLogic interface { 28 | FormatKey(string) string 29 | 30 | FormatMap(string, map[string]string) string 31 | FormatArray(string, []string) string 32 | FormatString(string, string) string 33 | FormatInt(string, int) string 34 | FormatFloat(string, float64) string 35 | FormatBool(string, bool) string 36 | FormatNill(string) string 37 | } 38 | -------------------------------------------------------------------------------- /components/converter_logic/converter_logic_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package converter_logic 17 | 18 | import ( 19 | "testing" 20 | ) 21 | 22 | func TestConverterLogic(t *testing.T) { 23 | 24 | tests := []struct{ 25 | name string 26 | logic ConverterLogic 27 | float, string, int, array_string string 28 | } { 29 | { 30 | name: "map", 31 | logic: CreateMapConverterLogic(), 32 | float: " 22.000000", 33 | string: ` "hello"`, 34 | int: " 22", 35 | 36 | array_string: "key = [\n hello,\n there,\n]", 37 | }, 38 | } 39 | 40 | testOut := func(name string, have string, want string) { 41 | if have != want { 42 | t.Errorf("Bad %s format have: %s\nwant: %s", name, have, want) 43 | } 44 | } 45 | 46 | 47 | for _, test := range tests { 48 | 49 | t.Run(test.name, func(t *testing.T) { 50 | 51 | testOut("float", test.logic.FormatFloat("", 22.0), test.float) 52 | testOut("string", test.logic.FormatString("", "hello"), test.string) 53 | 54 | testOut("int", test.logic.FormatInt("", 22), test.int) 55 | testOut("[]string", test.logic.FormatArray("key", []string{"hello", "there"}), test.array_string) 56 | }) 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /components/converter_logic/default_converter_logic.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package converter_logic 17 | 18 | // 19 | // This creates what we consider to be the "default" dredger 20 | // converter logic. In this case convert arrays to maps and 21 | // everything else to block format. e.g. 22 | // 23 | // section { 24 | // foo = "value" 25 | // bar = [1,2,3] 26 | // } 27 | // 28 | 29 | func CreateDefaultConverterLogic() ConverterLogic { 30 | mapConverter := mapConverterLogic{} 31 | blockConverter := blockConverterLogic{} 32 | 33 | return joinedConverterLogic{ 34 | mapConverter: blockConverter, 35 | arrayConverter: mapConverter, 36 | scalarConverter: blockConverter, 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /components/converter_logic/joined_converter_logic.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package converter_logic 17 | 18 | // 19 | // Joined converter logic is an interface coupler allowing different 20 | // logic to be used for maps arrays and scalars. 21 | // 22 | 23 | type joinedConverterLogic struct { 24 | mapConverter ConverterLogic 25 | arrayConverter ConverterLogic 26 | scalarConverter ConverterLogic 27 | } 28 | 29 | func (dl joinedConverterLogic) FormatKey(k string) string { 30 | return dl.mapConverter.FormatKey(k) 31 | } 32 | 33 | func (dl joinedConverterLogic) FormatMap(k string, m map[string]string) string { 34 | return dl.mapConverter.FormatMap(k, m) 35 | } 36 | 37 | func (dl joinedConverterLogic) FormatArray(k string, a []string) string { 38 | return dl.arrayConverter.FormatArray(k, a) 39 | } 40 | 41 | func (dl joinedConverterLogic) FormatString(k string, v string) string { 42 | return dl.scalarConverter.FormatString(k, v) 43 | } 44 | 45 | func (dl joinedConverterLogic) FormatInt(k string, v int) string { 46 | return dl.scalarConverter.FormatInt(k, v) 47 | } 48 | 49 | func (dl joinedConverterLogic) FormatFloat(k string, v float64) string { 50 | return dl.scalarConverter.FormatFloat(k, v) 51 | } 52 | 53 | func (dl joinedConverterLogic) FormatBool(k string, v bool) string { 54 | return dl.scalarConverter.FormatBool(k, v) 55 | } 56 | 57 | func (dl joinedConverterLogic) FormatNill(k string) string { 58 | return dl.scalarConverter.FormatNill(k) 59 | } 60 | -------------------------------------------------------------------------------- /components/converter_logic/map_converter_logic.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package converter_logic 17 | 18 | import ( 19 | "fmt" 20 | "github.com/synchronoss/dredger/components/map_utils" 21 | "github.com/synchronoss/dredger/components/terraform_format" 22 | ) 23 | 24 | // 25 | // converter logic for terraform "map" format e.g. 26 | // 27 | // section = { 28 | // "key" = "value" 29 | // "foo" = [ { "bar":22 }, { "baz":420 } ] 30 | // } 31 | // 32 | 33 | type mapConverterLogic struct{} 34 | 35 | func (dl mapConverterLogic) FormatKey(k string) string { 36 | return terraform_format.Quote(terraform_format.SnakeCase(k)) 37 | } 38 | 39 | func (dl mapConverterLogic) FormatMap(k string, m map[string]string) string { 40 | 41 | var content = "" 42 | 43 | // Itterate through the keys in sorted order (for consistency) 44 | for _, k := range map_utils.SortKeysString(m) { 45 | 46 | // The sub-value already contains the key so just append 47 | // to the content with a newline. 48 | content += m[k] + "\n" 49 | } 50 | 51 | // Indent the whole content. 52 | indentContent := terraform_format.Indent(content) 53 | 54 | // Build the braced leaf-string 55 | key := terraform_format.AssignKey(k) 56 | return fmt.Sprintf("%s {\n%s\n}", key, indentContent) 57 | } 58 | 59 | func (dl mapConverterLogic) FormatArray(k string, a []string) string { 60 | var content = "" 61 | 62 | for _, v := range a { 63 | content += v + ",\n" 64 | } 65 | 66 | indentContent := terraform_format.Indent(content) 67 | 68 | key := terraform_format.AssignKey(k) 69 | return fmt.Sprintf("%s [\n%s\n]", key, indentContent) 70 | } 71 | 72 | func (dl mapConverterLogic) FormatString(k string, v string) string { 73 | key := terraform_format.AssignKey(k) 74 | s := terraform_format.FormatStringValue(v) 75 | return fmt.Sprintf("%s %s", key, s) 76 | } 77 | 78 | func (dl mapConverterLogic) FormatInt(k string, v int) string { 79 | key := terraform_format.AssignKey(k) 80 | return fmt.Sprintf("%s %d", key, v) 81 | } 82 | 83 | func (dl mapConverterLogic) FormatFloat(k string, v float64) string { 84 | key := terraform_format.AssignKey(k) 85 | return fmt.Sprintf("%s %f", key, v) 86 | } 87 | 88 | func (dl mapConverterLogic) FormatBool(k string, v bool) string { 89 | key := terraform_format.AssignKey(k) 90 | return fmt.Sprintf("%s %t", key, v) 91 | } 92 | 93 | func (dl mapConverterLogic) FormatNill(k string) string { 94 | key := terraform_format.AssignKey(k) 95 | return fmt.Sprintf("%s null", key) 96 | } 97 | 98 | func CreateMapConverterLogic() ConverterLogic { 99 | return mapConverterLogic{} 100 | } 101 | -------------------------------------------------------------------------------- /components/debug/debug.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package debug 17 | 18 | import ( 19 | "fmt" 20 | "os" 21 | ) 22 | 23 | // Just a debug function which can be enabled via 24 | // an env var DEBUG=on 25 | 26 | var printDebug = os.Getenv("DEBUG") == "on" 27 | 28 | func Debug(msg ...interface{}) { 29 | if printDebug { 30 | fmt.Println(msg...) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /components/document_leaf/document_leaf.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package document_leaf 17 | 18 | // 19 | // Document leaf is the wrapper structure 20 | // used to present data to the templating engine 21 | // 22 | // It consists of the "actual" values and the "substitute" 23 | // values that would have been rendered had a policy not matched. 24 | // 25 | // As a result this is basically a Leaf and ParsedLeaf combined. 26 | // But due to the way that go templating works they are presented 27 | // as members of a single object 28 | 29 | type DocumentLeaf struct { 30 | Key string 31 | Doc interface{} 32 | Sub string 33 | Trail string 34 | SubValue interface{} 35 | Value interface{} 36 | } 37 | -------------------------------------------------------------------------------- /components/encoding/encoding.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package encoding 17 | 18 | import ( 19 | "github.com/synchronoss/dredger/components/debug" 20 | "gopkg.in/yaml.v3" 21 | s "strings" 22 | ) 23 | 24 | // 25 | // Just a function to decode multi-document YAML 26 | // into an array of interfaces. 27 | // 28 | 29 | func DecodeDocumentList(input string) ([]interface{}, error) { 30 | var ret = []interface{}{} 31 | 32 | // Split the documents by the yaml seperator 33 | documentStrings := s.Split(input, "\n---\n") 34 | 35 | for _, documentString := range documentStrings { 36 | 37 | // Skip if the document is empty 38 | if s.Trim(documentString, " \n\t") == "" { 39 | debug.Debug("skipping empty document") 40 | continue 41 | } 42 | 43 | documentStruct := map[string]interface{}{} 44 | 45 | yamlErr := yaml.Unmarshal([]byte(documentString), &documentStruct) 46 | if yamlErr != nil { 47 | return ret, yamlErr 48 | } 49 | 50 | if len(documentStruct) == 0 { 51 | continue 52 | } 53 | 54 | ret = append(ret, documentStruct) 55 | } 56 | 57 | return ret, nil 58 | } 59 | -------------------------------------------------------------------------------- /components/encoding/encoding_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package encoding 17 | 18 | import ( 19 | "testing" 20 | ) 21 | 22 | const testDoc = ` 23 | --- 24 | one: 1 25 | --- 26 | two: 2 27 | ` 28 | 29 | func TestEncoding(t *testing.T) { 30 | 31 | documents, err := DecodeDocumentList(testDoc) 32 | 33 | if err != nil { 34 | t.Fatal(err) 35 | } 36 | 37 | if 2 != len(documents) { 38 | t.Fatalf("Wrong number of documents, expected 2 got %d", len(documents)) 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /components/input_source/helm_input_source.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package input_source 17 | 18 | import ( 19 | "github.com/synchronoss/dredger/components/debug" 20 | "github.com/synchronoss/dredger/components/encoding" 21 | "os/exec" 22 | "bytes" 23 | "errors" 24 | ) 25 | 26 | type helmInputSource struct { 27 | args []string 28 | } 29 | 30 | func (hi helmInputSource) ReadDocuments() ([]interface{}, error) { 31 | 32 | var docs []interface{} 33 | 34 | staticArgs := []string{"template", "${var.name}", "--namespace", "${var.namespace}"} 35 | 36 | args := append(staticArgs, hi.args...) 37 | 38 | path, err := exec.LookPath("helm") 39 | 40 | if err != nil { 41 | return docs, err 42 | } 43 | 44 | cmdArgs := append([]string{"helm"}, args...) 45 | 46 | debug.Debug("running helm with args", cmdArgs) 47 | 48 | cmd := exec.Cmd{ 49 | Path: path, 50 | Args: cmdArgs, 51 | } 52 | 53 | var stdout, stderr bytes.Buffer 54 | cmd.Stdout = &stdout 55 | cmd.Stderr = &stderr 56 | 57 | runErr := cmd.Run() 58 | 59 | if runErr != nil { 60 | return docs, errors.New(string(stderr.Bytes())) 61 | } 62 | 63 | return encoding.DecodeDocumentList(string(stdout.Bytes())) 64 | } 65 | -------------------------------------------------------------------------------- /components/input_source/input_source.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package input_source 17 | 18 | import "fmt" 19 | 20 | // 21 | // InputSource represents any source that can produce document lists 22 | // for conversion. 23 | // 24 | 25 | type InputSource interface { 26 | ReadDocuments() ([]interface{}, error) 27 | } 28 | 29 | func CreateInputSource(mode string, args []string) (InputSource, error) { 30 | switch mode { 31 | case "stdin": 32 | return stdinInputSource{}, nil 33 | case "helm": 34 | return helmInputSource{ args:args }, nil 35 | default: 36 | return nil, fmt.Errorf("unknown input source: %s", mode) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /components/input_source/stdin_input_source.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package input_source 17 | 18 | // 19 | // stdinInputSource reads all documents from stdin and assumes YAML encoding 20 | // 21 | 22 | import ( 23 | "github.com/synchronoss/dredger/components/encoding" 24 | "io/ioutil" 25 | "os" 26 | ) 27 | 28 | type stdinInputSource struct{} 29 | 30 | func (si stdinInputSource) ReadDocuments() ([]interface{}, error) { 31 | 32 | bytes, err := ioutil.ReadAll(os.Stdin) 33 | 34 | if err != nil { 35 | return nil, err 36 | } 37 | 38 | asString := string(bytes) 39 | 40 | return encoding.DecodeDocumentList(asString) 41 | } 42 | -------------------------------------------------------------------------------- /components/leaf/leaf.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package leaf 17 | 18 | import ( 19 | "fmt" 20 | "github.com/synchronoss/dredger/components/converter_logic" 21 | "github.com/synchronoss/dredger/components/debug" 22 | "github.com/synchronoss/dredger/components/document_leaf" 23 | "github.com/synchronoss/dredger/components/parsed_leaf" 24 | "github.com/synchronoss/dredger/components/policy_set" 25 | ) 26 | 27 | type Leaf interface { 28 | Process() (parsed_leaf.ParsedLeaf, error) 29 | } 30 | 31 | func CreateLeaf(doc interface{}, logic converter_logic.ConverterLogic, policies policy_set.PolicySet) Leaf { 32 | return leaf{ 33 | key: "", 34 | trail: "", 35 | doc: doc, 36 | value: doc, 37 | logic: logic, 38 | policies: policies, 39 | } 40 | } 41 | 42 | func CreateConverterLeaf(doc interface{}, key string, logic converter_logic.ConverterLogic) Leaf { 43 | return leaf{ 44 | key: key, 45 | trail: key, 46 | doc: doc, 47 | value: doc, 48 | logic: logic, 49 | policies: policy_set.CreateEmptyPolicySet(), 50 | } 51 | } 52 | 53 | type leaf struct { 54 | logic converter_logic.ConverterLogic 55 | policies policy_set.PolicySet 56 | trail string 57 | key string 58 | value interface{} 59 | doc interface{} 60 | } 61 | 62 | func (l leaf) Process() (parsed_leaf.ParsedLeaf, error) { 63 | subLeaf, subErr := l.determineSub() 64 | 65 | if subErr != nil { 66 | return nil, subErr 67 | } 68 | 69 | if l.policies.Match() { 70 | debug.Debug("!! policy match at", l.trail) 71 | 72 | docLeaf := document_leaf.DocumentLeaf{ 73 | Key: l.key, 74 | Trail: l.trail, 75 | Value: l.value, 76 | Sub: subLeaf.GetLeaf(), 77 | Doc: l.doc, 78 | SubValue: subLeaf.GetValue(), 79 | } 80 | 81 | policyLeaf, policyErr := l.policies.Execute(&docLeaf) 82 | 83 | if policyErr != nil { 84 | return nil, policyErr 85 | } 86 | 87 | return policyLeaf.JoinUnits(subLeaf), nil 88 | } else { 89 | return subLeaf, nil 90 | } 91 | } 92 | 93 | func (l leaf) determineSub() (parsed_leaf.ParsedLeaf, error) { 94 | 95 | v := l.value 96 | 97 | if v == nil { 98 | return l.convertNill() 99 | } 100 | 101 | switch v.(type) { 102 | case map[string]interface{}: 103 | return l.convertMap() 104 | case []interface{}: 105 | return l.convertArray() 106 | case string: 107 | return l.convertString() 108 | case int: 109 | return l.convertInt() 110 | case float64: 111 | return l.convertFloat() 112 | case bool: 113 | return l.convertBool() 114 | default: 115 | return nil, fmt.Errorf("Unknown type produced in YAML: %T", v) 116 | } 117 | 118 | } 119 | 120 | func (l leaf) convertNill() (parsed_leaf.ParsedLeaf, error) { 121 | debug.Debug("converting nill at", l.trail) 122 | stringValue := l.logic.FormatNill(l.key) 123 | return parsed_leaf.Create(stringValue), nil 124 | } 125 | 126 | func (l leaf) convertMap() (parsed_leaf.ParsedLeaf, error) { 127 | debug.Debug("converting map at", l.trail) 128 | asMap := l.value.(map[string]interface{}) 129 | 130 | // Detremine the "sub" values first. 131 | sub := map[string]string{} 132 | 133 | // An empty parsed_leaf.ParsedLeaf is created 134 | // to merge the sub values with 135 | var parsed = parsed_leaf.Create("") 136 | for k, v := range asMap { 137 | 138 | subPolicySet := l.policies.Reduce(k) 139 | 140 | formatKey := l.logic.FormatKey(k) 141 | 142 | subLeaf := leaf{ 143 | key: formatKey, 144 | value: v, 145 | logic: l.logic, 146 | policies: subPolicySet, 147 | doc: l.doc, 148 | trail: l.trail + "." + formatKey, 149 | } 150 | 151 | subOut, err := subLeaf.Process() 152 | 153 | if err != nil { 154 | return subOut, err 155 | } 156 | 157 | // Join the sub-parsed-leaf's units to 158 | // our sub-value. 159 | parsed = parsed.JoinUnits(subOut) 160 | 161 | subText := subOut.GetLeaf() 162 | 163 | if subText == "" { 164 | continue 165 | } 166 | 167 | // Add to the sub-map 168 | sub[k] = subText 169 | } 170 | 171 | formatted := l.logic.FormatMap(l.key, sub) 172 | 173 | return parsed.SetLeaf(formatted).SetValue(sub), nil 174 | } 175 | 176 | func (l leaf) convertArray() (parsed_leaf.ParsedLeaf, error) { 177 | debug.Debug("converting array at", l.trail) 178 | asArray := l.value.([]interface{}) 179 | 180 | // Determine the "sub" value 181 | 182 | var sub []string 183 | var parsed = parsed_leaf.Create("") 184 | 185 | // Iterate through the items and convert 186 | for i, v := range asArray { 187 | k := fmt.Sprintf("%d", i) 188 | 189 | // Reduce the policies for this key 190 | subPolicySet := l.policies.Reduce(k) 191 | 192 | // Create a sub-leaf 193 | subLeaf := leaf{ 194 | key: "", 195 | value: v, 196 | logic: l.logic, 197 | policies: subPolicySet, 198 | doc: l.doc, 199 | trail: l.trail + "." + k, 200 | } 201 | 202 | subOut, err := subLeaf.Process() 203 | 204 | if err != nil { 205 | return nil, err 206 | } 207 | 208 | // Add the sub-units to the return leaf 209 | parsed = parsed.JoinUnits(subOut) 210 | 211 | subText := subOut.GetLeaf() 212 | 213 | if subText == "" { 214 | continue 215 | } 216 | 217 | sub = append(sub, subText) 218 | 219 | } 220 | 221 | formatted := l.logic.FormatArray(l.key, sub) 222 | 223 | return parsed.SetLeaf(formatted).SetValue(sub), nil 224 | } 225 | 226 | // 227 | // These methods just refer to the converter logic but wrap in leaves. 228 | // 229 | 230 | func (l leaf) convertString() (parsed_leaf.ParsedLeaf, error) { 231 | debug.Debug("converting string at", l.trail) 232 | stringValue := l.logic.FormatString(l.key, l.value.(string)) 233 | return parsed_leaf.Create(stringValue), nil 234 | } 235 | 236 | func (l leaf) convertInt() (parsed_leaf.ParsedLeaf, error) { 237 | debug.Debug("converting int at", l.trail) 238 | stringValue := l.logic.FormatInt(l.key, l.value.(int)) 239 | return parsed_leaf.Create(stringValue), nil 240 | } 241 | 242 | func (l leaf) convertFloat() (parsed_leaf.ParsedLeaf, error) { 243 | debug.Debug("converting float at", l.trail) 244 | stringValue := l.logic.FormatFloat(l.key, l.value.(float64)) 245 | return parsed_leaf.Create(stringValue), nil 246 | } 247 | 248 | func (l leaf) convertBool() (parsed_leaf.ParsedLeaf, error) { 249 | debug.Debug("converting bool at", l.trail) 250 | stringValue := l.logic.FormatBool(l.key, l.value.(bool)) 251 | return parsed_leaf.Create(stringValue), nil 252 | } 253 | -------------------------------------------------------------------------------- /components/map_utils/sort_keys.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package map_utils 17 | 18 | import ( 19 | "sort" 20 | ) 21 | 22 | // Functions to sort the keys of a map. These are required for 23 | // consistency as golang randomises map key order. 24 | // 25 | // And as golang doesn't have templates we have to create multiple 26 | // functions or use reflection. 27 | // 28 | // This is exactly why I don't like golang 29 | 30 | func SortKeysInterface(m map[string]interface{}) []string { 31 | var keys []string 32 | 33 | for k := range m { 34 | keys = append(keys, k) 35 | } 36 | 37 | sort.Strings(keys) 38 | return keys 39 | } 40 | 41 | func SortKeysString(m map[string]string) []string { 42 | var keys []string 43 | 44 | for k := range m { 45 | keys = append(keys, k) 46 | } 47 | 48 | sort.Strings(keys) 49 | return keys 50 | } 51 | -------------------------------------------------------------------------------- /components/output_target/directory_output_target.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package output_target 17 | 18 | import ( 19 | "errors" 20 | "io/ioutil" 21 | "fmt" 22 | "os" 23 | ) 24 | 25 | // 26 | // An output target to write each leaf/unit file to it's own file 27 | // 28 | 29 | type directoryOutputTarget struct { 30 | directory string 31 | } 32 | 33 | func (dt directoryOutputTarget) determinFileName(unitPath string) string { 34 | return dt.directory + "/" + unitPath + ".tf" 35 | } 36 | 37 | func (dt directoryOutputTarget) writeWorldReadableFile(fileName string, data string) error { 38 | return ioutil.WriteFile(fileName, []byte(data), 0644) 39 | } 40 | 41 | func (dt directoryOutputTarget) writeUnitFile(unitPath string, data string) error { 42 | fileName := dt.determinFileName(unitPath) 43 | fmt.Println("writing unit", fileName) 44 | return dt.writeWorldReadableFile(fileName, data) 45 | } 46 | 47 | func (dt directoryOutputTarget) Init() error { 48 | return os.MkdirAll(dt.directory, os.ModePerm) 49 | } 50 | 51 | func (do directoryOutputTarget) WriteLeaf(p ParsedLeaf) error { 52 | for _, unit := range p.GetAllUnits() { 53 | unitPath := DetermineUnitPath(unit) 54 | 55 | if unitPath == "" { 56 | return errors.New("Failed to determine unit path") 57 | } 58 | 59 | writeErr := do.writeUnitFile(unitPath, unit) 60 | 61 | if writeErr != nil { 62 | return writeErr 63 | } 64 | } 65 | 66 | return nil 67 | } 68 | -------------------------------------------------------------------------------- /components/output_target/output_target.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package output_target 17 | 18 | import ( 19 | "github.com/synchronoss/dredger/components/parsed_leaf" 20 | ) 21 | 22 | // 23 | // OutputTarget is any destination for converted documents 24 | // 25 | 26 | type ParsedLeaf = parsed_leaf.ParsedLeaf 27 | 28 | type OutputTarget interface { 29 | Init() error 30 | WriteLeaf(ParsedLeaf) error 31 | } 32 | 33 | func CreateOutputTarget(outputDir string) OutputTarget { 34 | if outputDir == "" { 35 | return stdoutOutputTarget{} 36 | } else { 37 | return directoryOutputTarget{directory: outputDir} 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /components/output_target/stdout_output_target.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package output_target 17 | 18 | import "fmt" 19 | 20 | // 21 | // An OutputTarget whereby the converted couemnts are just 22 | // written to stdout 23 | // 24 | 25 | type stdoutOutputTarget struct{} 26 | 27 | func (st stdoutOutputTarget) Init() error { 28 | // No init is required 29 | return nil 30 | } 31 | 32 | func (st stdoutOutputTarget) WriteLeaf(p ParsedLeaf) error { 33 | for _, unit := range p.GetAllUnits() { 34 | fmt.Println(unit) 35 | } 36 | return nil 37 | } 38 | -------------------------------------------------------------------------------- /components/output_target/unit_path.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package output_target 17 | 18 | import ( 19 | "regexp" 20 | s "strings" 21 | ) 22 | 23 | // 24 | // This function tries to create a unique string from a leaf/unit. 25 | // 26 | // e.g. 27 | // resource "kubernetes_statefulset" "foo" => resource_kubernetes_statefulset_foo 28 | // 29 | // This is used to determine the filename when writing output to a directory. 30 | // 31 | 32 | var declerationRegex = regexp.MustCompile(`(?m)^(resource|variable|output|module|provider) (:?("\S+"\s*))+{\s*$`) 33 | var alpha = regexp.MustCompile(`(\w+)`) 34 | 35 | func DetermineUnitPath(unit string) string { 36 | 37 | match := declerationRegex.FindStringSubmatch(unit) 38 | 39 | if len(match) == 0 { 40 | return "" 41 | } 42 | 43 | alphas := alpha.FindAllString(match[0], -1) 44 | 45 | return s.Join(alphas, "_") 46 | } 47 | -------------------------------------------------------------------------------- /components/parsed_leaf/parsed_leaf.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package parsed_leaf 17 | 18 | // 19 | // ParsedLeaf represents a POST-rendering document leaf. 20 | // 21 | // It also includes additional units which have to propegate 22 | // up to the root. 23 | // 24 | 25 | type ParsedLeaf interface { 26 | GetLeaf() string 27 | GetUnits() []string 28 | GetValue() interface{} 29 | GetAllUnits() []string 30 | SetLeaf(string) ParsedLeaf 31 | SetValue(interface{}) ParsedLeaf 32 | AddUnits(...string) ParsedLeaf 33 | JoinUnits(ParsedLeaf) ParsedLeaf 34 | } 35 | 36 | type parsedLeaf struct { 37 | leaf string 38 | units []string 39 | value interface{} 40 | } 41 | 42 | func (l parsedLeaf) GetValue() interface{} { return l.value } 43 | func (l parsedLeaf) GetLeaf() string { return l.leaf } 44 | func (l parsedLeaf) GetUnits() []string { return l.units } 45 | func (l parsedLeaf) GetAllUnits() []string { return append(l.units, l.leaf) } 46 | 47 | func (l parsedLeaf) SetLeaf(newLeaf string) ParsedLeaf { 48 | l.leaf = newLeaf 49 | return l 50 | } 51 | 52 | func (l parsedLeaf) SetValue(newValue interface{}) ParsedLeaf { 53 | l.value = newValue 54 | return l 55 | } 56 | 57 | func (l parsedLeaf) AddUnits(newUnits ...string) ParsedLeaf { 58 | l.units = append(l.units, newUnits...) 59 | return l 60 | } 61 | 62 | func (l parsedLeaf) JoinUnits(r ParsedLeaf) ParsedLeaf { 63 | return l.AddUnits(r.GetUnits()...) 64 | } 65 | 66 | func Create(leaf string) ParsedLeaf { 67 | return &parsedLeaf{leaf: leaf} 68 | } 69 | -------------------------------------------------------------------------------- /components/policy/policy.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package policy 17 | 18 | import ( 19 | "github.com/synchronoss/dredger/components/document_leaf" 20 | "github.com/synchronoss/dredger/components/parsed_leaf" 21 | ) 22 | 23 | type DocumentLeaf = document_leaf.DocumentLeaf 24 | type ParsedLeaf = parsed_leaf.ParsedLeaf 25 | 26 | type Policy interface { 27 | Execute(*DocumentLeaf) (ParsedLeaf, error) 28 | PopKey(string) Policy 29 | MatchKey(string) bool 30 | FullMatch() bool 31 | } 32 | -------------------------------------------------------------------------------- /components/policy/template_policy.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package policy 17 | 18 | import ( 19 | "github.com/synchronoss/dredger/components/config" 20 | "github.com/synchronoss/dredger/components/parsed_leaf" 21 | "github.com/synchronoss/dredger/components/policy_path" 22 | "github.com/synchronoss/dredger/components/template" 23 | s "strings" 24 | ) 25 | 26 | type Template = template.Template 27 | type FuncMap = template.FuncMap 28 | 29 | type templatePolicy struct { 30 | tpl Template 31 | unitTpls []Template 32 | path policy_path.PolicyPath 33 | } 34 | 35 | func (tp templatePolicy) Execute(leaf *DocumentLeaf) (ParsedLeaf, error) { 36 | leafString, err := tp.tpl.Execute(leaf) 37 | if err != nil { 38 | return parsed_leaf.Create(""), err 39 | } 40 | 41 | var ret = parsed_leaf.Create(leafString) 42 | 43 | for _, unitTpl := range tp.unitTpls { 44 | unitString, unitErr := unitTpl.Execute(leaf) 45 | if unitErr != nil { 46 | return ret, unitErr 47 | } 48 | 49 | // units may return empty so trim and check if we should 50 | // ignore it 51 | trimmedString := s.Trim(unitString, "\n \t") 52 | if trimmedString != "" { 53 | ret = ret.AddUnits(trimmedString + "\n") 54 | } 55 | } 56 | 57 | return ret, nil 58 | } 59 | 60 | func (tp templatePolicy) MatchKey(key string) bool { 61 | return tp.path.MatchKey(key) 62 | } 63 | 64 | func (tp templatePolicy) FullMatch() bool { 65 | return tp.path.FullMatch() 66 | } 67 | 68 | func (tp templatePolicy) PopKey(key string) Policy { 69 | tp.path = tp.path.PopKey(key) 70 | return tp 71 | } 72 | 73 | func BuildPolicy(policyConfig *config.PolicyConfig, funcMap FuncMap) (Policy, error) { 74 | 75 | goTpl, goTplError := template.CreateTemplate("template", funcMap, policyConfig.Template) 76 | 77 | if goTplError != nil { 78 | return nil, goTplError 79 | } 80 | 81 | var unitTpls []Template 82 | 83 | for _, unitTemplate := range policyConfig.UnitTemplate { 84 | unitTpl, unitTplError := template.CreateTemplate("unit_template", funcMap, unitTemplate) 85 | 86 | if unitTplError != nil { 87 | return nil, unitTplError 88 | } 89 | unitTpls = append(unitTpls, unitTpl) 90 | } 91 | 92 | path := policy_path.Create(policyConfig.Path) 93 | 94 | return templatePolicy{path: path, tpl: goTpl, unitTpls: unitTpls}, nil 95 | } 96 | -------------------------------------------------------------------------------- /components/policy_path/policy_path.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package policy_path 17 | 18 | import ( 19 | s "strings" 20 | ) 21 | 22 | // 23 | // PolicyPath defines the data and logic for a policy path expression. 24 | // 25 | // An exmaple of a policy path is foo.**.baz.*.bar 26 | 27 | type PolicyPath interface { 28 | MatchKey(string) bool 29 | FullMatch() bool 30 | PopKey(string) PolicyPath 31 | } 32 | 33 | type policyPath struct { 34 | path []string 35 | } 36 | 37 | func (pp policyPath) MatchKey(key string) bool { 38 | return len(pp.path) > 0 && (pp.path[0] == "*" || pp.path[0] == "**" || pp.path[0] == key) 39 | } 40 | 41 | func (pp policyPath) FullMatch() bool { 42 | return len(pp.path) == 0 43 | } 44 | 45 | func (pp policyPath) PopKey(key string) PolicyPath { 46 | p := pp.path 47 | if p[0] == "**" { 48 | if p[1] == key { 49 | pp.path = p[2:] 50 | } 51 | } else { 52 | pp.path = p[1:] 53 | } 54 | 55 | return pp 56 | } 57 | 58 | func Create(path string) PolicyPath { 59 | 60 | var ret = s.Split(path, ".") 61 | // If the path is an empty string just return 62 | // an empty array. Otherise it would match root. 63 | if len(ret) == 1 && ret[0] == "" { 64 | ret = []string{} 65 | } 66 | 67 | return policyPath{path: ret} 68 | } 69 | -------------------------------------------------------------------------------- /components/policy_path/policy_path_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package policy_path 17 | 18 | import ( 19 | "testing" 20 | ) 21 | 22 | func TestCreate(t *testing.T) { 23 | 24 | testStrings := []string{"foo.**.bar.*.baz"} 25 | 26 | for _, testString := range testStrings { 27 | t.Run(testString, func(t *testing.T) { 28 | path := Create(testString) 29 | 30 | if path == nil { 31 | t.Fatalf("Create returns a null for string") 32 | } 33 | }) 34 | 35 | } 36 | } 37 | 38 | func TestMatch(t *testing.T) { 39 | 40 | match := []string{"foo", "bar", "baz"} 41 | 42 | tests := []struct { 43 | path string 44 | count int 45 | }{ 46 | {path: "foo.bar.baz", count: 3}, 47 | {path: "foo.*.baz", count: 3}, 48 | {path: "**.baz", count: 3}, 49 | {path: "foo.bar", count: 2}, 50 | {path: "foo", count: 1}, 51 | {path: "bar", count: 0}, 52 | {path: "foo.**.baz", count: 3}, 53 | {path: "**.*.baz", count: 3}, 54 | {path: "*.**.baz", count: 3}, 55 | } 56 | 57 | for _, test := range tests { 58 | 59 | t.Run(test.path, func(t *testing.T) { 60 | 61 | var path = Create(test.path) 62 | 63 | var count = 0 64 | 65 | for _, m := range match { 66 | 67 | if path.FullMatch() { 68 | break 69 | } else if path.MatchKey(m) { 70 | path = path.PopKey(m) 71 | count += 1 72 | } else { 73 | break 74 | } 75 | } 76 | 77 | if count != test.count { 78 | t.Fatalf("Path %s has incorrect match. Got %d expected %d", test.path, count, test.count) 79 | } 80 | 81 | }) 82 | 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /components/policy_set/basic_policy_set.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package policy_set 17 | 18 | import ( 19 | "github.com/synchronoss/dredger/components/parsed_leaf" 20 | "github.com/synchronoss/dredger/components/policy" 21 | ) 22 | 23 | type ( 24 | Policy = policy.Policy 25 | ) 26 | 27 | type basicPolicySet struct { 28 | policies []Policy 29 | } 30 | 31 | func (ps basicPolicySet) Execute(docLeaf *DocumentLeaf) (ParsedLeaf, error) { 32 | for _, p := range ps.policies { 33 | if p.FullMatch() { 34 | return p.Execute(docLeaf) 35 | } 36 | } 37 | return parsed_leaf.Create(""), nil 38 | } 39 | 40 | func (ps basicPolicySet) Match() bool { 41 | for _, p := range ps.policies { 42 | if p.FullMatch() { 43 | return true 44 | } 45 | } 46 | return false 47 | } 48 | 49 | func (ps basicPolicySet) Reduce(key string) PolicySet { 50 | var newPolicies []Policy 51 | 52 | for _, pol := range ps.policies { 53 | if pol.MatchKey(key) { 54 | newPolicies = append(newPolicies, pol.PopKey(key)) 55 | } 56 | } 57 | 58 | ps.policies = newPolicies 59 | return ps 60 | } 61 | -------------------------------------------------------------------------------- /components/policy_set/policy_set.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package policy_set 17 | 18 | import ( 19 | "github.com/synchronoss/dredger/components/config" 20 | "github.com/synchronoss/dredger/components/document_leaf" 21 | "github.com/synchronoss/dredger/components/parsed_leaf" 22 | "github.com/synchronoss/dredger/components/policy" 23 | ) 24 | 25 | // 26 | // PolicySet 27 | // 28 | 29 | type ( 30 | DocumentLeaf = document_leaf.DocumentLeaf 31 | ParsedLeaf = parsed_leaf.ParsedLeaf 32 | Config = config.Config 33 | FuncMap = policy.FuncMap 34 | ) 35 | 36 | type PolicySet interface { 37 | Reduce(string) PolicySet 38 | Match() bool 39 | Execute(*DocumentLeaf) (ParsedLeaf, error) 40 | } 41 | 42 | func CreatePolicySet(policies []policy.Policy) PolicySet { 43 | return basicPolicySet{policies: policies} 44 | } 45 | 46 | func CreateEmptyPolicySet() PolicySet { 47 | return basicPolicySet{policies: []policy.Policy{}} 48 | } 49 | 50 | func BuildPolicies(config *Config, funcMap *FuncMap) (PolicySet, error) { 51 | var policies []Policy 52 | 53 | for _, policyConfig := range config.Policies { 54 | 55 | policy, policyErr := policy.BuildPolicy(&policyConfig, *funcMap) 56 | 57 | if policyErr != nil { 58 | return nil, policyErr 59 | } 60 | 61 | policies = append(policies, policy) 62 | } 63 | 64 | return basicPolicySet{policies: policies}, nil 65 | } 66 | -------------------------------------------------------------------------------- /components/template/template.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package template 17 | 18 | import ( 19 | "bytes" 20 | "github.com/synchronoss/dredger/components/document_leaf" 21 | "html" 22 | "html/template" 23 | ) 24 | 25 | type FuncMap = template.FuncMap 26 | type DocumentLeaf = document_leaf.DocumentLeaf 27 | 28 | // 29 | // Template 30 | // 31 | // Just wraps around html/template and makes it a little more sane 32 | 33 | type Template interface { 34 | Execute(*DocumentLeaf) (string, error) 35 | } 36 | 37 | type goTemplate struct { 38 | goTpl *template.Template 39 | } 40 | 41 | func (tpl goTemplate) Execute(leaf *DocumentLeaf) (string, error) { 42 | var buf bytes.Buffer 43 | err := tpl.goTpl.Execute(&buf, leaf) 44 | if err != nil { 45 | return "", err 46 | } 47 | return html.UnescapeString(buf.String()), nil 48 | } 49 | 50 | func CreateTemplate(name string, funcMap FuncMap, body string) (Template, error) { 51 | tpl, tplError := template.New(name).Funcs(funcMap).Parse(body) 52 | 53 | if tplError != nil { 54 | return nil, tplError 55 | } 56 | 57 | return &goTemplate{goTpl: tpl}, nil 58 | } 59 | -------------------------------------------------------------------------------- /components/template/template_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package template 17 | 18 | import ( 19 | "testing" 20 | ) 21 | 22 | func TestTemplate(t *testing.T) { 23 | 24 | template, templateErr := CreateTemplate("test", FuncMap{}, "Key = {{ $.Key }}") 25 | 26 | if templateErr != nil { 27 | t.Fatal(templateErr) 28 | } 29 | 30 | docLeaf := DocumentLeaf{ 31 | Key: "foo", 32 | } 33 | 34 | output, err := template.Execute(&docLeaf) 35 | 36 | if err != nil { 37 | t.Fatal(err) 38 | } 39 | 40 | if output != "Key = foo" { 41 | t.Fatalf("Unexpected output, got %s", output) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /components/template_function_map/create_function_map.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package template_function_map 17 | 18 | import ( 19 | "fmt" 20 | "github.com/Masterminds/sprig" 21 | "github.com/synchronoss/dredger/components/converter_logic" 22 | "github.com/synchronoss/dredger/components/leaf" 23 | "github.com/synchronoss/dredger/components/policy_set" 24 | "github.com/synchronoss/dredger/components/terraform_format" 25 | ) 26 | 27 | // 28 | // Creates the in-built functions which we extend go-templates with. 29 | // 30 | // These include things such as toOctal. 31 | // 32 | 33 | type BoundConverter = func(interface{}, string) (string, error) 34 | 35 | func bindLogicConverter(logic converter_logic.ConverterLogic) BoundConverter { 36 | 37 | return func(v interface{}, k string) (string, error) { 38 | l := leaf.CreateConverterLeaf(v, k, logic) 39 | 40 | p, err := l.Process() 41 | if err != nil { 42 | return "", err 43 | } 44 | 45 | return p.GetLeaf(), nil 46 | } 47 | } 48 | 49 | func CreateFunctionMap() *policy_set.FuncMap { 50 | funcMap := sprig.FuncMap() 51 | 52 | blockLogic := converter_logic.CreateBlockConverterLogic() 53 | funcMap["toTfBlock"] = bindLogicConverter(blockLogic) 54 | 55 | mapLogic := converter_logic.CreateMapConverterLogic() 56 | funcMap["toTfMap"] = bindLogicConverter(mapLogic) 57 | 58 | funcMap["toOctal"] = func(v int) string { 59 | return fmt.Sprintf("%#o", v) 60 | } 61 | 62 | funcMap["stripTfVars"] = terraform_format.StripVars 63 | funcMap["formatTfString"] = terraform_format.FormatStringValue 64 | funcMap["formatResourceName"] = terraform_format.FormatResourceName 65 | 66 | return &funcMap 67 | } 68 | -------------------------------------------------------------------------------- /components/terraform_format/escape_non_tf_vars.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package terraform_format 17 | 18 | import ( 19 | "regexp" 20 | s "strings" 21 | ) 22 | 23 | // 24 | // EscapeNonTfVars 25 | // 26 | // Escape any non-terraform variables 27 | 28 | var matchNonTfVar = regexp.MustCompile("(\\${[^}]+})") 29 | 30 | func escapePrefix(v string) string { 31 | if s.HasPrefix(v, "${var.") || s.HasPrefix(v, "${local.") { 32 | return v 33 | } else { 34 | return "$$" + EscapeNonTfVars(s.TrimPrefix(v, "$")) 35 | } 36 | } 37 | 38 | func EscapeNonTfVars(v string) string { 39 | return matchNonTfVar.ReplaceAllStringFunc(v, escapePrefix) 40 | } 41 | -------------------------------------------------------------------------------- /components/terraform_format/format_key.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package terraform_format 17 | 18 | import ( 19 | s "strings" 20 | ) 21 | 22 | // AssignKey 23 | // 24 | // Set a key to be "key = " as long as key is not empty. 25 | 26 | func AssignKey(k string) string { 27 | if k == "" || k == `""` { 28 | return "" 29 | } else { 30 | return k + " =" 31 | } 32 | } 33 | 34 | func FormatKey(str string) string { 35 | stripped := StripVars(str) 36 | underscored := s.Replace(stripped, "-", "_", -1) 37 | return SnakeCase(underscored) 38 | } 39 | -------------------------------------------------------------------------------- /components/terraform_format/format_resource_name.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package terraform_format 18 | 19 | import ( 20 | s "strings" 21 | ) 22 | 23 | func FormatResourceName(str string) string { 24 | str = StripVars(str) 25 | str = s.Replace(str, ".", "_", -1) 26 | return str 27 | } 28 | -------------------------------------------------------------------------------- /components/terraform_format/format_string_value.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package terraform_format 17 | 18 | import ( 19 | "regexp" 20 | s "strings" 21 | ) 22 | 23 | // 24 | // FormatStringValue 25 | // 26 | // - unwrap interpolation only strings 27 | // - escape non-terraform vars 28 | // - quote of not var-only 29 | // 30 | 31 | func isMultiLine(str string) bool { 32 | lines := s.Split(str, "\n") 33 | return len(lines) > 1 34 | } 35 | 36 | var interpolationOnlyVar = regexp.MustCompile(`^\${(var\.[^}]+)}$`) 37 | var interpolationOnlyLocal = regexp.MustCompile(`^\${(local\.[^}]+)}$`) 38 | 39 | 40 | func FormatStringValue(v string) string { 41 | v = EscapeNonTfVars(v) 42 | if interpolationOnlyVar.MatchString(v) { 43 | return interpolationOnlyVar.ReplaceAllString(v, "$1") 44 | } else if interpolationOnlyLocal.MatchString(v) { 45 | return interpolationOnlyLocal.ReplaceAllString(v, "$1") 46 | } else if isMultiLine(v) { 47 | return "<<-EOF\n" + Indent(v) + "\n EOF" + "\n" 48 | } else { 49 | return Quote(v) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /components/terraform_format/indent.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package terraform_format 17 | 18 | import ( 19 | s "strings" 20 | ) 21 | 22 | // 23 | // indent 24 | // 25 | // Indent a block of text by two spaces 26 | // 27 | 28 | func Indent(str string) string { 29 | lines := s.Split(str, "\n") 30 | var ret []string 31 | 32 | for _, line := range lines { 33 | if len(line) > 0 { 34 | ret = append(ret, " "+line) 35 | } 36 | } 37 | 38 | return s.Join(ret, "\n") 39 | } 40 | -------------------------------------------------------------------------------- /components/terraform_format/quote.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package terraform_format 17 | 18 | import ( 19 | s "strings" 20 | ) 21 | 22 | // 23 | // Quote 24 | // 25 | // Wraps a string in double quotes while escaping any 26 | // existing ones 27 | // 28 | 29 | func Quote(str string) string { 30 | var escapedStr = str 31 | //@TODO Check this 32 | escapedStr = s.Replace(escapedStr, `\`, `\\`, -1) 33 | escapedStr = s.Replace(escapedStr, `\"`, `\\"`, -1) 34 | escapedStr = s.Replace(escapedStr, `"`, `\"`, -1) 35 | return `"` + escapedStr + `"` 36 | } 37 | -------------------------------------------------------------------------------- /components/terraform_format/snake_case.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package terraform_format 17 | 18 | import ( 19 | "regexp" 20 | s "strings" 21 | ) 22 | 23 | // SnakeCase 24 | // 25 | // Convert a string to snake case. 26 | // 27 | // Terraform always uses snake case. 28 | 29 | var matchFirstCap = regexp.MustCompile("(.)([A-Z][a-z]+)") 30 | var matchAllCap = regexp.MustCompile("([a-z0-9])([A-Z])") 31 | 32 | func SnakeCase(str string) string { 33 | snake := matchFirstCap.ReplaceAllString(str, "${1}_${2}") 34 | snake = matchAllCap.ReplaceAllString(snake, "${1}_${2}") 35 | return s.ToLower(snake) 36 | } 37 | -------------------------------------------------------------------------------- /components/terraform_format/strip_vars.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package terraform_format 17 | 18 | import ( 19 | "regexp" 20 | ) 21 | 22 | // StripVars 23 | // 24 | // Remove any interpolated variables from a string 25 | 26 | var matchVar = regexp.MustCompile("-?\\${var\\.[^}]+}-?") 27 | 28 | func StripVars(str string) string { 29 | return matchVar.ReplaceAllString(str, "") 30 | } 31 | -------------------------------------------------------------------------------- /components/terraform_format/terraform_format_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package terraform_format 17 | 18 | import ( 19 | "testing" 20 | ) 21 | 22 | type Test struct { 23 | original string 24 | snake string 25 | indent string 26 | quote string 27 | strip string 28 | formatString string 29 | formatKey string 30 | } 31 | 32 | func RunTests(t *testing.T, cbk func(string) string, extract func(Test) string) { 33 | 34 | tests := []Test{ 35 | {original: "fooBar", snake: "foo_bar", indent: " fooBar", quote: `"fooBar"`}, 36 | {original: "bazBar", snake: "baz_bar", indent: " bazBar", quote: `"bazBar"`}, 37 | {original: `"hello"`, quote: `"\"hello\""`}, 38 | {original: "${var.foo}bar", strip: "bar"}, 39 | {original: "${var.foo}-baz", strip: "baz", formatKey: "baz", formatString: `"${var.foo}-baz"`}, 40 | {original: "${var.foo}", formatString: "var.foo"}, 41 | {original: "foo", formatString: `"foo"`}, 42 | {original: "${var.foo}\n${var.bar}", formatString: "<<-EOF\n ${var.foo}\n ${var.bar}\n EOF\n"}, 43 | {original: "${var.name}-foo-bar", formatKey: "foo_bar"}, 44 | } 45 | 46 | for _, test := range tests { 47 | expect := extract(test) 48 | 49 | if expect == "" { 50 | continue 51 | } 52 | 53 | t.Run(test.original, func(t *testing.T) { 54 | 55 | result := cbk(test.original) 56 | 57 | if expect != result { 58 | t.Errorf("Conversion failed\nwant: %s\nhave: %s", expect, result) 59 | } 60 | }) 61 | } 62 | 63 | } 64 | 65 | func TestSnakeCase(t *testing.T) { 66 | RunTests(t, SnakeCase, func(test Test) string { return test.snake }) 67 | } 68 | 69 | func TestIndent(t *testing.T) { 70 | RunTests(t, Indent, func(test Test) string { return test.indent }) 71 | } 72 | 73 | func TestQuote(t *testing.T) { 74 | RunTests(t, Quote, func(test Test) string { return test.quote }) 75 | } 76 | 77 | func TestStripVars(t *testing.T) { 78 | RunTests(t, StripVars, func(test Test) string { return test.strip }) 79 | } 80 | 81 | func TestFormatString(t *testing.T) { 82 | RunTests(t, FormatStringValue, func(test Test) string { return test.formatString }) 83 | } 84 | 85 | func TestFormatKey(t *testing.T) { 86 | RunTests(t, FormatKey, func(test Test) string { return test.formatKey }) 87 | } 88 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/synchronoss/dredger 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.24.2 6 | 7 | require ( 8 | github.com/Masterminds/sprig v2.22.0+incompatible 9 | gopkg.in/yaml.v3 v3.0.1 10 | ) 11 | 12 | require ( 13 | github.com/Masterminds/goutils v1.1.1 // indirect 14 | github.com/Masterminds/semver v1.5.0 // indirect 15 | github.com/davecgh/go-spew v1.1.0 // indirect 16 | github.com/google/go-cmp v0.6.0 // indirect 17 | github.com/google/uuid v1.6.0 // indirect 18 | github.com/huandu/xstrings v1.5.0 // indirect 19 | github.com/imdario/mergo v0.3.16 // indirect 20 | github.com/mitchellh/copystructure v1.2.0 // indirect 21 | github.com/mitchellh/reflectwalk v1.0.2 // indirect 22 | github.com/pmezard/go-difflib v1.0.0 // indirect 23 | github.com/stretchr/objx v0.1.0 // indirect 24 | github.com/stretchr/testify v1.7.0 // indirect 25 | github.com/yuin/goldmark v1.4.13 // indirect 26 | golang.org/x/crypto v0.37.0 // indirect 27 | golang.org/x/mod v0.17.0 // indirect 28 | golang.org/x/net v0.25.0 // indirect 29 | golang.org/x/sync v0.13.0 // indirect 30 | golang.org/x/sys v0.32.0 // indirect 31 | golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2 // indirect 32 | golang.org/x/term v0.31.0 // indirect 33 | golang.org/x/text v0.24.0 // indirect 34 | golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect 35 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 // indirect 36 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 // indirect 37 | gopkg.in/yaml.v2 v2.3.0 // indirect 38 | ) 39 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= 2 | github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= 3 | github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= 4 | github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= 5 | github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= 6 | github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= 7 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 8 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 9 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 10 | github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= 11 | github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 12 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 13 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 14 | github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= 15 | github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= 16 | github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= 17 | github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= 18 | github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= 19 | github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= 20 | github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= 21 | github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= 22 | github.com/mitchellh/copystructure v1.1.1 h1:Bp6x9R1Wn16SIz3OfeDr0b7RnCG2OB66Y7PQyC/cvq4= 23 | github.com/mitchellh/copystructure v1.1.1/go.mod h1:EBArHfARyrSWO/+Wyr9zwEkc6XMFB9XyNgFNmRkZZU4= 24 | github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= 25 | github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= 26 | github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= 27 | github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 28 | github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= 29 | github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 30 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 31 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 32 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 33 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 34 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 35 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 36 | golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= 37 | golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 38 | golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= 39 | golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= 40 | golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 41 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 42 | golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 43 | golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= 44 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 45 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 46 | golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= 47 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 48 | golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= 49 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 50 | golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= 51 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 52 | golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= 53 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 54 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 55 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 56 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 57 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 58 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 59 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 60 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 61 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 62 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Synchronoss Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "flag" 21 | "fmt" 22 | "github.com/synchronoss/dredger/components/config" 23 | "github.com/synchronoss/dredger/components/converter_logic" 24 | "github.com/synchronoss/dredger/components/input_source" 25 | "github.com/synchronoss/dredger/components/leaf" 26 | "github.com/synchronoss/dredger/components/output_target" 27 | "github.com/synchronoss/dredger/components/parsed_leaf" 28 | "github.com/synchronoss/dredger/components/policy_set" 29 | "github.com/synchronoss/dredger/components/template_function_map" 30 | "os" 31 | ) 32 | 33 | const ( 34 | version = "0.4.5" 35 | ) 36 | 37 | var ( 38 | dumpConfig bool 39 | versionFlag bool 40 | configFile string 41 | outputDir string 42 | ) 43 | 44 | func panicOnErr(err error) { 45 | if err != nil { 46 | panic(err) 47 | } 48 | } 49 | 50 | func main() { 51 | 52 | // Parse the command line flags 53 | flag.BoolVar(&dumpConfig, "dumpconfig", false, "Dump the default config") 54 | flag.BoolVar(&versionFlag, "version", false, "Display the version and exit") 55 | flag.StringVar(&configFile, "config", "", "Specify a new config file") 56 | flag.StringVar(&outputDir, "outputdir", "", "Split units into files and write to dir") 57 | flag.Parse() 58 | 59 | // If dumpconfig flag was passed just write the config and exit 60 | if dumpConfig { 61 | baseConfig := config.LoadDefaultConfig() 62 | fmt.Println(baseConfig) 63 | os.Exit(0) 64 | } 65 | 66 | // If version flag was passed just write the version and exit 67 | if versionFlag { 68 | fmt.Println(version) 69 | os.Exit(0) 70 | } 71 | 72 | args := flag.Args() 73 | 74 | // Determine the input mode and seperate out the helm arguments 75 | var mode string = "stdin" 76 | var extraArgs []string 77 | 78 | if len(args) > 0 { 79 | mode = args[0] 80 | extraArgs = args[1:] 81 | } 82 | 83 | // Create input source 84 | inputSource, inputSourceErr := input_source.CreateInputSource(mode, extraArgs) 85 | panicOnErr(inputSourceErr) 86 | 87 | // Read documents from input source 88 | documents, decodeErr := inputSource.ReadDocuments() 89 | panicOnErr(decodeErr) 90 | 91 | // Load the config 92 | config, configErr := config.LoadConfig(configFile) 93 | panicOnErr(configErr) 94 | 95 | // Generate template function map 96 | funcMap := template_function_map.CreateFunctionMap() 97 | 98 | // Build the initial policy set 99 | rootPolicySet, rootPolicyErr := policy_set.BuildPolicies(config, funcMap) 100 | panicOnErr(rootPolicyErr) 101 | 102 | // Create the output target 103 | outputTarget := output_target.CreateOutputTarget(outputDir) 104 | 105 | // Initialize the output target 106 | outputTargetInitErr := outputTarget.Init() 107 | panicOnErr(outputTargetInitErr) 108 | 109 | // We need a default logic converter 110 | converterLogic := converter_logic.CreateDefaultConverterLogic() 111 | 112 | // If we reach this point then we always output the static units 113 | for _, staticUnit := range config.StaticUnits { 114 | staticLeaf := parsed_leaf.Create(staticUnit) 115 | outputTarget.WriteLeaf(staticLeaf) 116 | } 117 | 118 | // Loop through the documents 119 | for _, doc := range documents { 120 | // Convert to terraform 121 | l := leaf.CreateLeaf(doc, converterLogic, rootPolicySet) 122 | parsedLeaf, parseErr := l.Process() 123 | panicOnErr(parseErr) 124 | 125 | // Write to the output target 126 | outputErr := outputTarget.WriteLeaf(parsedLeaf) 127 | panicOnErr(outputErr) 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /release: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | version=$1 5 | 6 | mkdir -p build 7 | 8 | build_target() { 9 | os=$1 10 | arch=$2 11 | suffix=${3:-""} 12 | dir=dredger-$version-$os-$arch 13 | echo building $dir 14 | mkdir -p $dir 15 | GOOS=$os GOARCH=$arch go build -o $dir/dredger$suffix main.go 16 | cp LICENSE $dir/LICENSE 17 | tar c $dir | gzip > build/$dir.tgz 18 | rm -rf $dir 19 | } 20 | 21 | build_target linux amd64 22 | build_target linux arm 23 | build_target windows amd64 ".exe" 24 | build_target darwin amd64 25 | build_target darwin arm64 26 | --------------------------------------------------------------------------------