├── .fixtures.yml ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .rspec ├── .rubocop.yml ├── Gemfile ├── LICENSE ├── README.md ├── REFERENCE.md ├── Rakefile ├── Vagrantfile ├── data └── common.yaml ├── hiera.yaml ├── manifests ├── agent.pp ├── config.pp ├── dahdi.pp ├── dotd │ └── file.pp ├── extensions.pp ├── feature.pp ├── iax.pp ├── init.pp ├── install.pp ├── language.pp ├── manager.pp ├── queue.pp ├── registry │ ├── iax.pp │ └── sip.pp ├── service.pp ├── sip.pp └── voicemail.pp ├── metadata.json ├── renovate.json ├── spec ├── classes │ └── init_spec.rb └── spec_helper.rb ├── templates ├── config_file.conf.epp ├── registry │ ├── iax.epp │ └── sip.epp └── snippet │ ├── agent.epp │ ├── feature.epp │ ├── manager.epp │ ├── queue.epp │ ├── sip.epp │ └── voicemail.epp ├── tests ├── Puppetfile ├── init.pp └── one_of_all.pp └── types ├── access.pp ├── extglobalvars.pp ├── featuremap.pp ├── featuresgeneral.pp ├── logfile.pp └── managerperms.pp /.fixtures.yml: -------------------------------------------------------------------------------- 1 | --- 2 | fixtures: 3 | symlinks: 4 | "asterisk": "#{source_dir}" 5 | forge_modules: 6 | "stdlib": 7 | repo: "puppetlabs/stdlib" 8 | ref: "8.5.0" 9 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | setup_matrix: 7 | name: 'Setup Test Matrix' 8 | runs-on: ubuntu-latest 9 | outputs: 10 | puppet_major_versions: ${{ steps.get-outputs.outputs.puppet_major_versions }} 11 | puppet_unit_test_matrix: ${{ steps.get-outputs.outputs.puppet_unit_test_matrix }} 12 | env: 13 | BUNDLE_WITHOUT: development:release 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: Setup ruby 17 | uses: ruby/setup-ruby@v1 18 | with: 19 | ruby-version: '2.7' 20 | bundler-cache: true 21 | - name: Run rake validate 22 | run: bundle exec rake validate 23 | - name: Run rake rubocop 24 | run: bundle exec rake rubocop 25 | - name: Setup Test Matrix 26 | id: get-outputs 27 | run: bundle exec metadata2gha --pidfile-workaround false 28 | 29 | unit: 30 | needs: setup_matrix 31 | runs-on: ubuntu-latest 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | include: ${{fromJson(needs.setup_matrix.outputs.puppet_unit_test_matrix)}} 36 | env: 37 | BUNDLE_WITHOUT: docs 38 | PUPPET_VERSION: "~> ${{ matrix.puppet }}.0" 39 | name: Puppet ${{ matrix.puppet }} (Ruby ${{ matrix.ruby }}) 40 | steps: 41 | - uses: actions/checkout@v4 42 | - name: Setup ruby 43 | uses: ruby/setup-ruby@v1 44 | with: 45 | ruby-version: ${{ matrix.ruby }} 46 | bundler-cache: true 47 | - name: Run tests 48 | run: bundle exec rake spec 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle 2 | .vagrant 3 | /pkg 4 | spec/fixtures 5 | /doc 6 | Gemfile.lock 7 | /.yardoc 8 | /vendor 9 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format documentation 3 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | require: rubocop-rspec 3 | AllCops: 4 | DisplayCopNames: true 5 | TargetRubyVersion: '2.7' 6 | NewCops: enable 7 | Exclude: 8 | - bin/* 9 | - ".vendor/**/*" 10 | - pkg/**/* 11 | - spec/fixtures/**/* 12 | - vendor/**/* 13 | Layout/EmptyLinesAroundAttributeAccessor: 14 | Enabled: true 15 | Layout/LineLength: 16 | Description: People have wide screens, use them. 17 | Max: 200 18 | Layout/SpaceAroundMethodCallOperator: 19 | Enabled: true 20 | Lint/BinaryOperatorWithIdenticalOperands: 21 | Enabled: true 22 | Lint/DeprecatedOpenSSLConstant: 23 | Enabled: true 24 | Lint/DuplicateElsifCondition: 25 | Enabled: true 26 | Lint/DuplicateRescueException: 27 | Enabled: true 28 | Lint/EmptyConditionalBody: 29 | Enabled: true 30 | Lint/FloatComparison: 31 | Enabled: true 32 | Lint/MissingSuper: 33 | Enabled: true 34 | Lint/MixedRegexpCaptureTypes: 35 | Enabled: true 36 | Lint/OutOfRangeRegexpRef: 37 | Enabled: true 38 | Lint/RaiseException: 39 | Enabled: true 40 | Lint/SelfAssignment: 41 | Enabled: true 42 | Lint/StructNewOverride: 43 | Enabled: true 44 | Lint/TopLevelReturnWithArgument: 45 | Enabled: true 46 | Lint/UnreachableLoop: 47 | Enabled: true 48 | RSpec/BeforeAfterAll: 49 | Description: Beware of using after(:all) as it may cause state to leak between tests. 50 | A necessary evil in acceptance testing. 51 | Exclude: 52 | - spec/acceptance/**/*.rb 53 | RSpec/HookArgument: 54 | Description: Prefer explicit :each argument, matching existing module's style 55 | EnforcedStyle: each 56 | Style/BlockDelimiters: 57 | Description: Prefer braces for chaining. Mostly an aesthetical choice. Better to 58 | be consistent then. 59 | EnforcedStyle: braces_for_chaining 60 | Style/ClassAndModuleChildren: 61 | Description: Compact style reduces the required amount of indentation. 62 | EnforcedStyle: compact 63 | Style/EmptyElse: 64 | Description: Enforce against empty else clauses, but allow `nil` for clarity. 65 | EnforcedStyle: empty 66 | Style/FormatString: 67 | Description: Following the main puppet project's style, prefer the % format format. 68 | EnforcedStyle: percent 69 | Style/FormatStringToken: 70 | Description: Following the main puppet project's style, prefer the simpler template 71 | tokens over annotated ones. 72 | EnforcedStyle: template 73 | Style/FrozenStringLiteralComment: 74 | Enabled: false 75 | Style/Lambda: 76 | Description: Prefer the keyword for easier discoverability. 77 | EnforcedStyle: literal 78 | Style/RegexpLiteral: 79 | Description: Community preference. See https://github.com/voxpupuli/modulesync_config/issues/168 80 | EnforcedStyle: percent_r 81 | Style/TernaryParentheses: 82 | Description: Checks for use of parentheses around ternary conditions. Enforce parentheses 83 | on complex expressions for better readability, but seriously consider breaking 84 | it up. 85 | EnforcedStyle: require_parentheses_when_complex 86 | Style/TrailingCommaInArguments: 87 | Description: Prefer always trailing comma on multiline argument lists. This makes 88 | diffs, and re-ordering nicer. 89 | EnforcedStyleForMultiline: comma 90 | Style/TrailingCommaInArrayLiteral: 91 | Description: Prefer always trailing comma on multiline literals. This makes diffs, 92 | and re-ordering nicer. 93 | EnforcedStyleForMultiline: comma 94 | Style/TrailingCommaInHashLiteral: 95 | Description: Prefer always trailing comma on multiline literals. This makes diffs, 96 | and re-ordering nicer. 97 | EnforcedStyleForMultiline: comma 98 | Style/SymbolArray: 99 | Description: Using percent style obscures symbolic intent of array's contents. 100 | EnforcedStyle: brackets 101 | RSpec/MessageSpies: 102 | EnforcedStyle: receive 103 | Style/CollectionMethods: 104 | Enabled: true 105 | Style/MethodCalledOnDoEndBlock: 106 | Enabled: true 107 | Style/StringMethods: 108 | Enabled: true 109 | Layout/EndOfLine: 110 | Enabled: false 111 | Metrics/AbcSize: 112 | Enabled: false 113 | Metrics/BlockLength: 114 | Enabled: false 115 | Metrics/ClassLength: 116 | Enabled: false 117 | Metrics/CyclomaticComplexity: 118 | Enabled: false 119 | Metrics/MethodLength: 120 | Enabled: false 121 | Metrics/ModuleLength: 122 | Enabled: false 123 | Metrics/ParameterLists: 124 | Enabled: false 125 | Metrics/PerceivedComplexity: 126 | Enabled: false 127 | RSpec/DescribeClass: 128 | Enabled: false 129 | RSpec/ExampleLength: 130 | Enabled: false 131 | RSpec/MessageExpectation: 132 | Enabled: false 133 | RSpec/MultipleExpectations: 134 | Enabled: false 135 | RSpec/NestedGroups: 136 | Enabled: false 137 | Style/AccessorGrouping: 138 | Enabled: true 139 | Style/ArrayCoercion: 140 | Enabled: true 141 | Style/AsciiComments: 142 | Enabled: false 143 | Style/BisectedAttrAccessor: 144 | Enabled: true 145 | Style/CaseLikeIf: 146 | Enabled: true 147 | Style/ExplicitBlockArgument: 148 | Enabled: true 149 | Style/ExponentialNotation: 150 | Enabled: true 151 | Style/GlobalStdStream: 152 | Enabled: true 153 | Style/HashAsLastArrayItem: 154 | Enabled: true 155 | Style/HashEachMethods: 156 | Enabled: true 157 | Style/HashLikeCase: 158 | Enabled: true 159 | Style/HashTransformKeys: 160 | Enabled: true 161 | Style/HashTransformValues: 162 | Enabled: true 163 | Style/IfUnlessModifier: 164 | Enabled: true 165 | Style/OptionalBooleanParameter: 166 | Enabled: true 167 | Style/RedundantAssignment: 168 | Enabled: true 169 | Style/RedundantFetchBlock: 170 | Enabled: true 171 | Style/RedundantFileExtensionInRequire: 172 | Enabled: true 173 | Style/RedundantRegexpCharacterClass: 174 | Enabled: true 175 | Style/RedundantRegexpEscape: 176 | Enabled: true 177 | Style/SingleArgumentDig: 178 | Enabled: true 179 | Style/SlicingWithRange: 180 | Enabled: true 181 | Style/StringConcatenation: 182 | Enabled: true 183 | Style/SymbolProc: 184 | Enabled: false 185 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | puppetversion = ENV.key?('PUPPET_VERSION') ? ENV['PUPPET_VERSION'].to_s : ['>= 3.3'] 4 | 5 | gem 'puppet', puppetversion 6 | gem 'rake' 7 | 8 | group :tests do 9 | gem 'facter', '>= 2.4.0' 10 | # Use info from metadata.json for tests 11 | gem 'puppetlabs_spec_helper', '>= 0.10.0' 12 | gem 'puppet-lint', '>= 2.3.0' 13 | gem 'puppet_metadata' 14 | gem 'rspec-puppet', '>= 2.4.0' 15 | # This draws in rubocop and other useful gems for puppet tests 16 | gem 'voxpupuli-test' 17 | end 18 | 19 | group :docs do 20 | gem 'puppet-strings' 21 | end 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Puppet module for Asterisk 2 | ========================== 3 | 4 | To install Asterisk on a server, simply use the following: 5 | 6 | ```puppet 7 | include asterisk 8 | ``` 9 | 10 | This will install a plain version of Asterisk without any extra 11 | features enabled. 12 | 13 | Users that are upgrading (e.g. switching or merging to current master) should 14 | consult the section named [Upgrade notices](#upgrade-notices) near the end. 15 | 16 | Requirements 17 | ------------ 18 | 19 | In order to use this module, you need the stdlib module from: 20 | 21 | https://github.com/puppetlabs/puppetlabs-stdlib 22 | 23 | You should also make sure that augeas is installed since it is used to enable 24 | the service in `/etc/default/asterisk`. 25 | 26 | Reference reading 27 | ----------------- 28 | 29 | Some good references to consult when it comes to Asterisk configuration are: 30 | 31 | * The most up to date reference and documentation for all configurations can 32 | be found in upstream default configuration files. They can also be found in 33 | the `asterisk-doc` debian package. 34 | * Online version of "Asterisk: The Definitive Guide" 3rd edition. This is 35 | definitely the best and most up to date documentation available. A must 36 | read for anyone that is configuring a PBX with Asterisk. Consult this 37 | reference if you need more information about any options that can be 38 | configured with this module. The web site mentions a 4th edition was 39 | released but it is not available online: http://asteriskdocs.org/ 40 | * A good reference for VoIP and Asterisk (some information might be outdated): 41 | http://www.voip-info.org/ 42 | * The Asterisk project wiki: https://wiki.asterisk.org/ 43 | 44 | Configuring Asterisk 45 | ==================== 46 | 47 | Parameters to the asterisk class 48 | -------------------------------- 49 | 50 | The main class has a couple of parameters that determine what is managed and 51 | how general configuration is set. 52 | 53 | * `$manage_service` is a boolean that determines whether puppet will ensure 54 | that the service is running. Default value is true. 55 | 56 | * `$manage_package` is a boolean that determines whether puppet will ensure 57 | that the package is installed. Default value is true. 58 | 59 | * `$package_name` can be used to override the name of the package that 60 | installs Asterisk. Default value is "asterisk". 61 | 62 | * `$service_name` can be used to override the name of the Asterisk service. 63 | Default value is "asterisk". 64 | 65 | * `$confdir` can be used to override the path to the Asterisk configuration. 66 | Default value is "/etc/asterisk". 67 | 68 | * `$purge_confdir` is a boolean that enables or disables (default) removal of 69 | all files inside `confdir` that are not managed by puppet. This makes sure 70 | that the state of your service is well known. 71 | 72 | * `$iax_general` is a hash of global options for IAX2. See section IAX2 73 | Options. 74 | 75 | * `$sip_general` is a hash of global options for SIP. See section SIP Options. 76 | 77 | * `$voicemail_general` is a hash of global options for voicemail. See section 78 | Voicemail Options. 79 | 80 | * `$extensions_general` is a hash of global options for extensions. See 81 | section Extensions Options. 82 | 83 | Options section. 84 | 85 | * `$features_general` and `$featuremap` are detailed in the Features Options 86 | section. 87 | 88 | * `$queues_general` is detailed in the Queues Options section. 89 | 90 | * `$modules_autoload`, `$modules_noload`, `$modules_load` and 91 | `$modules_global` are detailed in the Modules section. 92 | 93 | * `$manager_enable`, `$manager_port` and `$manager_bindaddr` are detailed in 94 | the Manager Options section. 95 | 96 | ### Setting options with the $xyz_general or $xyz_global parameters ### 97 | 98 | Asterisk has lots and lots of configuration variables that can be set in 99 | different files. 100 | 101 | As you will see in some of the following configuration sections, some 102 | configuration files will be customizable through option hashes. The format of 103 | those hashes is always the same and looks like the following, where xyz would 104 | match the name of the configuration file: 105 | 106 | ```puppet 107 | $xyz_general = { 108 | 'configuration-option1' => 'value1', 109 | 'allow' => ['list-value1', 'list-value2'], 110 | #[...] 111 | } 112 | ``` 113 | 114 | In order to simplify the module, we're actually not validating that the options 115 | passed in are valid ones and expect this validation to be done by the user. 116 | 117 | We encourage users to use strings as hash keys as in the example above since 118 | some Asterisk options have dashes in their name and dashes are prohibited in 119 | puppet DSL symbols. 120 | 121 | Some options should always be arrays: the option can be specified in the 122 | configuration file more than once to declare more values. Those options will 123 | always be set in the hashes that define default values (see in each section 124 | below) as arrays either containing a number of strings, or being empty. The 125 | module enforces that those options be arrays since it needs to iterate over them 126 | in templates. Empty arrays mean that the option should not appear in the 127 | configuration file. 128 | 129 | Default values are taken from Debian's default configuration files. 130 | 131 | Keys that are present in the option hash paramters to the `asterisk` class will 132 | override the default options (or set new ones for options that are not present 133 | in the default option hash). This lets you use all the default values but 134 | change only a couple of values. 135 | 136 | Source or content 137 | ----------------- 138 | 139 | Most of the defined types that drop a configuration file in a .d directory can 140 | either take a puppet source specification (of the form 'puppet:///modules/...' 141 | or a textual content. 142 | 143 | The puppet source specification is always used with the `source` parameter and 144 | textual content with the `content` parameter. 145 | 146 | When using a puppet source specification the user has complete control over the 147 | contents of the configuration file. When textual content is used, the contents 148 | will usually be added after a line that defines a configuration section (e.g. a 149 | line of the form '[section]'). 150 | 151 | `source` and `content` are always mutually exclusive. 152 | 153 | IAX2 154 | ---- 155 | 156 | The `asterisk::iax` defined type helps you configure an IAX2 channel. `source` 157 | or `content` can be used with this type. 158 | 159 | ```puppet 160 | asterisk::iax { '5551234567': 161 | source => 'puppet:///modules/site_asterisk/5551234567', 162 | } 163 | ``` 164 | 165 | The `asterisk::registry::iax` defined type is used to configure an IAX2 166 | registry. All parameters (except for ensure) are mandatory. For example: 167 | 168 | ```puppet 169 | asterisk::registry::iax { 'providerX': 170 | server => 'iax.providerX.com', 171 | user => 'doyoufindme', 172 | pass => 'attractive?', 173 | } 174 | ``` 175 | 176 | ### IAX2 Options ### 177 | 178 | If you are using the IAX2 protocol, you'll want to set some global 179 | configuration options. For passing in settings, you need to send a hash to the 180 | `asterisk` class with the `iax_general` parameter. 181 | 182 | Here is the default hash with the default values, as defined in params.pp: 183 | 184 | ```puppet 185 | $iax_general = { 186 | 'allow' => [], 187 | 'disallow' => ['lpc10'], 188 | 'bandwidth' => 'low', 189 | 'jitterbuffer' => 'no', 190 | 'forcejitterbuffer' => 'no', 191 | 'autokill' => 'yes', 192 | 'delayreject' => 'yes', 193 | } 194 | ``` 195 | 196 | SIP 197 | --- 198 | 199 | You can configure SIP channels with the `asterisk::sip` defined type. `source` 200 | and `content` can be used with this type. 201 | 202 | ```puppet 203 | asterisk::sip { '1234': 204 | ensure => present, 205 | secret => 'blah', 206 | context => 'incoming', 207 | } 208 | ``` 209 | 210 | You can also use the `template_name` argument to either define a template, or 211 | make the channel definition inherit from a template. 212 | 213 | To define a template, set `template_name` to '!': 214 | 215 | ```puppet 216 | asterisk::sip { 'corporate_user': 217 | context => 'corporate', 218 | type => 'friend', 219 | # ... 220 | template_name => '!', 221 | } 222 | ``` 223 | 224 | If inheriting from a template, set `template_name` to 225 | the name of the template from which the channel is inheriting options. 226 | 227 | ```puppet 228 | asterisk::sip { 'hakim': 229 | secret => 'ohnoes!', 230 | template_name => 'corporate_user', 231 | } 232 | ``` 233 | 234 | The defined type `asterisk::registry::sip` lets you configure a SIP registry. 235 | The `server` and `user` paramters are mandatory. 236 | 237 | ```puppet 238 | asterisk::registry::sip { 'providerX': 239 | server => 'sip.providerX.com', 240 | user => 'doyoufindme', 241 | } 242 | ``` 243 | 244 | Password, authuser, port number and extension are optional parameters. If you 245 | define authuser, you must specify a password. 246 | 247 | ```puppet 248 | asterisk::registry::sip { 'friends_home': 249 | server => 'home.friend.com', 250 | port => '8888', 251 | user => 'me', 252 | password => 'myselfandI', 253 | authuser => 'you', 254 | extension => 'whatsupfriend', 255 | } 256 | ``` 257 | 258 | 259 | ### SIP Options ### 260 | 261 | If you are using the SIP protocol, you'll want to set some global 262 | configuration options. For passing in settings, you need to send a hash to the 263 | `asterisk` class with the `sip_general` parameter. 264 | 265 | Here is the default hash with the default values, as defined in params.pp: 266 | 267 | ```puppet 268 | $sip_general = { 269 | 'disallow' => [], 270 | 'allow' => [], 271 | 'domain' => [], 272 | 'localnet' => [], 273 | 'context' => 'default', 274 | 'allowoverlap' => 'no', 275 | 'udpbindaddr' => '0.0.0.0', 276 | 'tcpenable' => 'no', 277 | 'tcpbindaddr' => '0.0.0.0', 278 | 'transport' => 'udp', 279 | 'srvlookup' => 'yes', 280 | 'allowguest' => 'no', 281 | 'alwaysauthreject' => 'yes', 282 | } 283 | ``` 284 | 285 | ### SIP encryption ### 286 | 287 | If you want to enable SIP encryption, you can set the following settings in the 288 | `sip_general` parameter to the `asterisk` class: 289 | 290 | ```puppet 291 | $sip_option = { 292 | 'transports' => ['tls'], 293 | 'encryption' => 'yes', 294 | 'tlsenable' => 'yes', 295 | # Change the following two values to the full paths where you're placing your 296 | # own certificat and CA files, respectively. 297 | 'tlscertfile' => '/etc/ssl/somecert.crt', 298 | 'tlscafile' => '/etc/ssl/someca.crt', 299 | # Only set this to 'yes' if you can't possibly get a verifiable certificate. 300 | 'tlsdontverifyserver' => 'no', 301 | } 302 | ``` 303 | 304 | Note: the 'transports' option needs to be an array, so even though you only 305 | enable 'tls' as a transport, you need to enclose the string inside an array. 306 | 307 | Voicemail 308 | --------- 309 | 310 | With the defined type `asterisk::voicemail` you can configure a voicemail. The 311 | `context` and `password` parameters are mandatory: 312 | 313 | ```puppet 314 | asterisk::voicemail { '3000': 315 | context => 'some_context', 316 | password => '5555', 317 | user_name => 'Bob Bobby', 318 | email => 'bob@bobby.comcom', 319 | } 320 | ``` 321 | 322 | You can also use the optional 'pager_email' parameter to set the email that 323 | should receive a page about new voice messages. 324 | 325 | And finally, the argument 'options' can take a hash of voicemail options like 326 | the following: 327 | 328 | ```puppet 329 | asterisk::voicemail { '3001': 330 | context => 'blah', 331 | password => '112233', 332 | options => { 'attach' => 'yes', 'delete' => 'yes' }, 333 | } 334 | ``` 335 | 336 | ### Voicemail Options ### 337 | 338 | Voicemail can be configured through a set of options in the `[general]` 339 | context. To set those options, you can pass values as a hash to the 340 | `voicemail_general` parameter to the main class. 341 | 342 | Here is the default hash with the default values, as defined in params.pp: 343 | 344 | ```puppet 345 | $voicemail_general = { 346 | 'format' => 'wav49|gsm|wav', 347 | 'serveremail' => 'asterisk', 348 | 'attach' => 'yes', 349 | 'skipms' => 3000, 350 | 'maxsilence' => 10, 351 | 'silencethreshold' => 128, 352 | 'maxlogins' => 3, 353 | # This is not really the default value for emailbody but it makes more 354 | # sense to be a bit more verbose by default. 355 | 'emailbody' => 'Dear ${VM_NAME}:\n\n\tjust wanted to let you know you were just ${IF($["${VM_CIDNUM}" = "${ORIG_VM_CIDNUM}"]?left:forwarded)} a ${VM_DUR} long message (number ${VM_MSGNUM})\nin mailbox ${VM_MAILBOX} from ${VM_CALLERID} <${VM_CIDNUM}>, on ${VM_DATE},\n${IF($["${VM_CIDNUM}" = "${ORIG_VM_CIDNUM}"]?so:(originally sent by ${ORIG_VM_CALLERID} on ${ORIG_VM_DATE})\nso)} you might want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n', 356 | 'emaildateformat' => '%A, %B %d, %Y at %r', 357 | 'pagerdateformat' => '%A, %B %d, %Y at %r', 358 | 'sendvoicemail' => 'yes', 359 | } 360 | ``` 361 | 362 | Extensions 363 | ---------- 364 | 365 | Extensions can be set with the `asterisk::extensions` defined type. `source` or 366 | `content` can be used with this type. 367 | 368 | ```puppet 369 | asterisk::extensions { 'incoming': 370 | ensure => present, 371 | content => template('site_asterisk/extensions/incoming.erb'), 372 | } 373 | ``` 374 | 375 | ### Extensions Options ### 376 | 377 | Some global options can be set for extensions. You can achieve that by passing 378 | a hash to the `extensions_general` parameter to the `asterisk` class. 379 | 380 | Here is the default hash with the default values, as defined in params.pp: 381 | 382 | ```puppet 383 | $extensions_general = { 384 | 'static' => 'yes', 385 | 'writeprotect' => 'no', 386 | 'clearglobalvars' => 'no', 387 | } 388 | ``` 389 | 390 | Note that by default no global variables (e.g. values set in the `[globals]` 391 | context) are set. To set global variables, you can use an 392 | `asterisk::extensions` resource with a context value of "globals". 393 | 394 | Agents 395 | ------ 396 | 397 | To define an agent you can use the `asterisk::agent` defined type. The `ext`, 398 | `password` and `agent_name` parameters are mandatory. 399 | 400 | To define a static agent: 401 | 402 | ```puppet 403 | asterisk::agent { 'joe': 404 | ext => '1001', 405 | password => '123413425', 406 | agent_name => 'Joe Bonham', 407 | } 408 | ``` 409 | 410 | You can also assign a static agent to one or more agent groups with the 411 | `groups` parameter. This parameter is a list of group names: 412 | 413 | ```puppet 414 | asterisk::agent { 'cindy': 415 | ext => '1002', 416 | password => '754326', 417 | agent_name => 'Cindy Rotterbauer', 418 | groups => ['1'] 419 | } 420 | ``` 421 | 422 | Static agents have some disadvantages compared to dynamic agents. For example, 423 | once assigned to a queue they cannot logout of that queue. For more information 424 | on how to setup dynamic agents, see: 425 | 426 | * [https://www.voip-info.org/asterisk-cmd-agentlogin](https://www.voip-info.org/asterisk-cmd-agentlogin) 427 | * [https://www.voip-info.org/asterisk-cmd-addqueuemember](https://www.voip-info.org/asterisk-cmd-addqueuemember) 428 | * [https://www.voip-info.org/asterisk-cmd-removequeuemember](https://www.voip-info.org/asterisk-cmd-removequeuemember) 429 | 430 | ### Agents Options ### 431 | 432 | Global options in the `[agents]` context can be set by passing a hash to the 433 | `agents_global` parameter to the `asterisk` class. By default this parameter 434 | doesn't define any global options. 435 | 436 | For creating agents, it is recommended to use the `asterisk::agent` defined 437 | type. 438 | 439 | Features 440 | -------- 441 | 442 | Features let you configure call parking and special numbers that trigger 443 | special functionality. The `asterisk::feature` defined type helps you 444 | configuring such features. The `options` parameter is mandatory. 445 | 446 | Define features that are contained within feature group "myfeaturegroup": 447 | 448 | ```puppet 449 | $ft_options = { 450 | 'pausemonitor' => '#1,self/callee,Pausemonitor', 451 | 'unpauseMonitor' => '#3,self/callee,UnPauseMonitor', 452 | } 453 | asterisk::feature { 'myfeaturegroup': 454 | options => $ft_options, 455 | } 456 | ``` 457 | 458 | A special section in the features configuration file, namely 459 | `[applicationmaps]` lets you define global features. The 460 | `asterisk::feature::applicationmap` defined type helps you configure such a 461 | global feature. The `feature` and `value` parameters are mandatory: 462 | 463 | ```puppet 464 | asterisk::feature::applicationmap { 'pausemonitor': 465 | feature => 'pausemonitor', 466 | value => '#1,self/callee,Pausemonitor', 467 | } 468 | ``` 469 | 470 | ### Features global configurations ### 471 | 472 | Some global feature options can be configured, like the default parkinglot, via 473 | the `features_general` parameter to the `asterisk` class. 474 | 475 | Here is the default hash with the default values, as defined in params.pp: 476 | 477 | ```puppet 478 | $features_general = { 479 | 'parkext' => '700', 480 | 'parkpos' => '701-720', 481 | 'context' => 'parkedcalls', 482 | } 483 | ``` 484 | 485 | A special context, `featuremap`, lets you configure global features. By 486 | default, no feature is configured. You can pass a hash to the 487 | `features_featuremap` parameter to the `asterisk` class to configure features 488 | in this context. 489 | 490 | Another special context, `applicationmap`, lets you configure dynamic features. 491 | To set entries in this context, you should use the 492 | `asterisk::feature::applicationmap` defined type. Note also that for dynamic 493 | features to work the DYNAMIC_FEATURES channel variable must be set by listing 494 | features enabled in the channel, separated by '#'. 495 | 496 | To configure additional feature contexts, you can use the `asterisk::feature` 497 | defined type. 498 | 499 | Queues 500 | ------ 501 | 502 | Asterisk can put call in queues, for example when all agents are busy and the call cannot get connected. To create a queue, you can use the `asterisk::queue` defined type: 503 | 504 | ```puppet 505 | asterisk::queue { 'frontline': 506 | ensure => present, 507 | stragegy => 'rrmemory', 508 | members => [ 509 | 'SIP/reception', 510 | 'SIP/secretary', 511 | ], 512 | maxlen => 30, 513 | timeout => 20, 514 | retry => 10, 515 | } 516 | ``` 517 | 518 | Call queues have lots of options and can interact with agents. Because of this 519 | we will not detail all of the parameters here. Please refer to the 520 | manifests/queue.pp file for the complete list of supported parameters. Also, 521 | for an in-depth coverage of call queueing, see: 522 | http://www.asteriskdocs.org/en/3rd_Edition/asterisk-book-html-chunk/asterisk-ACD.html 523 | 524 | ### Queues Options ### 525 | 526 | For queues some global configurations and default values can be set in the 527 | `[general]` context. You can set options by passing a hash to the 528 | `queues_general` parameter to the `asterisk` class. 529 | 530 | Here is the default hash with the default values, as defined in params.pp: 531 | 532 | ```puppet 533 | $queues_general = { 534 | 'persistentmembers' => 'yes', 535 | 'monitor-type' => 'MixMonitor', 536 | } 537 | ``` 538 | 539 | Modules 540 | ------- 541 | 542 | Configuring Asterisk modules is key to implementing your features right. Four 543 | parameter to the `asterisk` class offer you the possibility to customize what 544 | modules are loaded or not on your PBX. Default values for the parameters were 545 | taken from the default config file in Debian. 546 | 547 | * `modules_autoload`: a boolean value (defaults to `true`) that decides 548 | whether or not Asterisk will try to automatically load required modules even 549 | though they are not explicitely marked as needing to be loaded in the 550 | modules.conf file. 551 | 552 | * `modules_noload`: an array of strings of explicitely unwanted modules that 553 | won't load even though `modules_autoload` is true. Specifying an array to 554 | this parameter overrides the default list so make sure to include all 555 | unwanted modules. The default array is the following: 556 | 557 | ```puppet 558 | $modules_noload = [ 559 | 'pbx_gtkconsole.so', 560 | 'pbx_kdeconsole.so', 561 | 'app_intercom.so', 562 | 'chan_modem.so', 563 | 'chan_modem_aopen.so', 564 | 'chan_modem_bestdata.so', 565 | 'chan_modem_i4l.so', 566 | 'chan_capi.so', 567 | 'chan_alsa.so', 568 | 'cdr_sqlite.so', 569 | 'app_directory_odbc.so', 570 | 'res_config_odbc.so', 571 | 'res_config_pgsql.so' 572 | ] 573 | ``` 574 | 575 | * `modules_load`: an array of strings of explicitely wanted modules. 576 | Specifying an array to this parameter overrides the default list so make 577 | sure to include all wanted modules. The default array is the following: 578 | 579 | ```puppet 580 | $modules_load = ['res_musiconhold.so'] 581 | ``` 582 | 583 | * `modules_global`: a hash of options that should be set in the 584 | `[global]` context. These options let you customize behaviours for modules 585 | that are loaded. 586 | 587 | Managers 588 | -------- 589 | 590 | Asterisk can expose an interface for managing the PBX. This interface can be 591 | offered to different users with different permissions. You can configure read 592 | and write access to certain features of the PBX for each user. 593 | 594 | The `asterisk::manager` defined type helps you configure a manager access. The 595 | `secret` parameter is mandatory. By default, the resource name is used as the 596 | manager name: 597 | 598 | ```puppet 599 | asterisk::manager { 'nagios': 600 | secret => 'topsecret1234', 601 | read => ['all'], 602 | write => ['system', ' call', ' log', ' verbose', ' command', ' agent', ' user'], 603 | } 604 | ``` 605 | 606 | Here's a paranoid version of the above configuration, with minimal network 607 | access, but the option to run system commands and trigger calls: 608 | 609 | ```puppet 610 | asterisk::manager { 'nagios': 611 | secret => 'topsecret1234', 612 | read => ['system', 'call'], 613 | write => ['system', 'call'], 614 | } 615 | ``` 616 | 617 | Here, we permit remote management to two other systems on an internal network: 618 | 619 | ```puppet 620 | asterisk::manager { 'robocall': 621 | secret => 'robotsdeservesomeloveafterall', 622 | permit => ['10.10.10.200/255.255.255.0', '10.20.20.200/255.255.255.0'], 623 | read => ['system', 'call', 'log'], 624 | write => ['system', 'call', 'originate'], 625 | } 626 | ``` 627 | 628 | To override the manager name, you can use the `manager_name` parameter: 629 | 630 | ```puppet 631 | asterisk::manager { 'sysadmin': 632 | secret => 'nowyouseemenowyoudont', 633 | read => ['all'], 634 | write => ['all'], 635 | manager_name => 'surreptitioustyrant', 636 | } 637 | ``` 638 | 639 | ### Manager Options ### 640 | 641 | Asterisk maintains a service on a port through which you can inspect asterisk's 642 | state and issue commands to the PBX. You can control on which IP and port it 643 | binds to and if it is enabled at all with three parameters to the `asterisk` 644 | class. 645 | 646 | * `manager_enable`: a boolean value that decides whether or not the manager is 647 | in function. Defaults to true. 648 | 649 | * `manager_port`: an integer value that specifies on which port the manager 650 | will listen. Default value is 5038. 651 | 652 | * `manager_bindaddr`: a string that contains the IP address on which the 653 | manager should bind. Default value is 127.0.0.1. 654 | 655 | By default, no user access is configured. If you want to enable users to 656 | interact with the manager, you should declare `asterisk::manager` 657 | resources. 658 | 659 | Dahdi 660 | ----- 661 | 662 | Dahdi is a set of kernel modules combined with an asterisk module that let 663 | people interact with Digium cards to send and receive calls from the POTS. To 664 | enable dahdi, use the following: 665 | 666 | ```puppet 667 | include 'asterisk::dahdi' 668 | ``` 669 | 670 | Language sounds 671 | --------------- 672 | 673 | To include any language sounds, you can use the following (in this example, 674 | we're installing french and spanish sounds): 675 | 676 | ```puppet 677 | asterisk::language { 678 | ['fr-armelle', 'es']: 679 | } 680 | ``` 681 | 682 | Valid languages strings are the following (these are all based on debian 683 | package names for now -- either asterisk-prompt-X or asterisk-Y. the language 684 | strings that start with core-sounds enable you to install language sounds in a 685 | specific encoding to avoid the need for asterisk to recode it while feeding it 686 | to a device): 687 | 688 | * de 689 | * es-co 690 | * fr-armelle 691 | * fr-proformatique 692 | * it-menardi 693 | * it-menardi-alaw 694 | * it-menardi-gsm 695 | * it-menardi-wav 696 | * se 697 | * es 698 | * core-sounds-en 699 | * core-sounds-en-g722 700 | * core-sounds-en-gsm 701 | * core-sounds-en-wav 702 | * core-sounds-es 703 | * core-sounds-es-g722 704 | * core-sounds-es-gsm 705 | * core-sounds-es-wav 706 | * core-sounds-fr 707 | * core-sounds-fr-g722 708 | * core-sounds-fr-gsm 709 | * core-sounds-fr-wav 710 | * core-sounds-ru 711 | * core-sounds-ru-g722 712 | * core-sounds-ru-gsm 713 | * core-sounds-ru-wav 714 | 715 | Upgrade notices 716 | =============== 717 | 718 | * The module used to manage files under /etc/asterisk/file.conf.d 719 | for all values of "file" that were managed. Things have been moved to 720 | /etc/asterisk/file.d, so before upgrading you should remove all .conf.d 721 | directories (all files under the old dirs will be automatically recreated in 722 | the new directories). 723 | 724 | * The defines that were previously named asterisk::context::xyz (or 725 | transitorily asterisk::snippet::xyz) are now named asterisk::xyz. Users will 726 | need to adjust their manifests to upgrade. 727 | 728 | * The `queues_monitor_type` and `queues_monitor_format` parameters to the 729 | default class were removed in favor of using quoted strings in the options 730 | array. Users who used those two options need to place their values in the 731 | `$queues_general` hash with 'monitor-type' and 'monitor-format' strings as 732 | keys, respectively. To ensure that 'monitor-type' is not present in the 733 | config file, simply leave it out (as opposed to the previous behaviour of 734 | the option that required an empty string for this). 735 | 736 | * Some default values were removed and some others were modified to be closer 737 | to default Debian config files. You should verify that new values or 738 | variables that disappear won't have an impact on your setup. 739 | 740 | Patches and Testing 741 | =================== 742 | 743 | Contributions are highly welcomed, more so are those which contribute patches 744 | with tests. Or just more tests! We have 745 | [rspec-puppet](http://rspec-puppet.com/) tests. 746 | When [contributing patches](Github WorkFlow), please make sure that your 747 | patches pass tests: 748 | 749 | user@host01 ~/src/bw/puppet-composer (git)-[master] % rake tests 750 | .................................... 751 | 752 | Finished in 2.29 seconds 753 | 36 examples, 0 failures 754 | 755 | 756 | Still not implemented ! 757 | ----------------------- 758 | 759 | Types: 760 | 761 | * `asterisk::mwi` 762 | 763 | License 764 | ======= 765 | 766 | This module is licensed under the GPLv3+, feel free to redistribute, modify and 767 | contribute changes. 768 | 769 | A copy of the GPLv3 license text should be included with the module. If not, 770 | check out the github repository at https://github.com/lelutin/puppet-asterisk 771 | or one of its clones. 772 | 773 | The license text can also be downloaded from: 774 | 775 | https://www.gnu.org/licenses/gpl-3.0.txt 776 | 777 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'puppetlabs_spec_helper/rake_tasks' 2 | require 'puppet-syntax/tasks/puppet-syntax' 3 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure('2') do |config| 5 | config.vm.box = 'debian/bullseye64' 6 | 7 | config.vm.define :test do |test| 8 | # This shell script will make sure that you have your module copied in 9 | # place with all of its current dependencies as they are declared in 10 | # metadata.json. 11 | # Note though that only the latest git commit will get deployed; you won't 12 | # be able to test changes that are still uncommitted. This is a bit 13 | # annoying. 14 | # Also, because librarian-puppet caches things, if you create a new commit 15 | # in the module, you will need to either destroy/up the VM or ssh in, and 16 | # run the following: 17 | # sudo -i 18 | # cd /tmp/vagrant-puppet 19 | # libraria-puppet clean 20 | # rm Puppetfile.lock 21 | # After the above you can run vagrant provision to test the newest commit. 22 | # 23 | # You do NOT want to have librarian-puppet work on a synced_dir if it's 24 | # using nfs: this could destroy all your files on the host. 25 | test.vm.provision 'install librarian-puppet and install dependencies', type: 'shell' do |s| 26 | s.inline = <<-SHELL 27 | apt-get update 28 | apt-get install -y librarian-puppet git 29 | cd /tmp/vagrant-puppet/ 30 | [[ -L Puppetfile ]] || ln -s /vagrant/tests/Puppetfile Puppetfile 31 | librarian-puppet install --verbose 32 | SHELL 33 | end 34 | 35 | test.vm.provision :puppet do |puppet| 36 | puppet.manifests_path = 'tests' 37 | # Change this to any file name in tests/ to run another test 38 | puppet.manifest_file = 'init.pp' 39 | puppet.options = ['--modulepath', '/tmp/vagrant-puppet/modules'] 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /data/common.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | asterisk::manage_service: true 3 | asterisk::manage_package: true 4 | asterisk::package_name: 5 | - 'asterisk' 6 | - 'asterisk-core-sounds-en' 7 | - 'asterisk-core-sounds-en-gsm' 8 | asterisk::service_name: 'asterisk' 9 | asterisk::confdir: '/etc/asterisk' 10 | asterisk::purge_confdir: false 11 | asterisk::iax_general: 12 | allow: [] 13 | disallow: 14 | - 'lpc10' 15 | bandwidth: 'low' 16 | jitterbuffer: 'no' 17 | forcejitterbuffer: 'no' 18 | autokill: 'yes' 19 | # Some added security default options 20 | delayreject: 'yes' 21 | asterisk::sip_general: 22 | disallow: [] 23 | allow: [] 24 | domain: [] 25 | localnet: [] 26 | context: 'default' 27 | allowoverlap: 'no' 28 | udpbindaddr: '0.0.0.0' 29 | tcpenable: 'no' 30 | tcpbindaddr: '0.0.0.0' 31 | transport: 'udp' 32 | srvlookup: 'yes' 33 | # Some added security default options 34 | allowguest: 'no' 35 | alwaysauthreject: 'yes' 36 | asterisk::voicemail_general: 37 | format: 'wav49|gsm|wav' 38 | serveremail: 'asterisk' 39 | attach: 'yes' 40 | skipms: 3000 41 | maxsilence: 10 42 | silencethreshold: 128 43 | maxlogins: 3 44 | # This is not really the default value for emailbody but it makes more 45 | # sense to be a bit more verbose by default. 46 | # NOTE: the value to this parameter needs to be on one line only and thus 47 | # it needs to contain litteral \n and \t character sequences. If the value 48 | # spans multiple lines, asterisk is confused about what's in the 49 | # configuration file. 50 | emailbody: 'Dear ${VM_NAME}:\n\n\tjust wanted to let you know you were just ${IF($["${VM_CIDNUM}" = "${ORIG_VM_CIDNUM}"]?left:forwarded)} a ${VM_DUR} long message (number ${VM_MSGNUM})\nin mailbox ${VM_MAILBOX} from ${VM_CALLERID} <${VM_CIDNUM}>, on ${VM_DATE},\n${IF($["${VM_CIDNUM}" = "${ORIG_VM_CIDNUM}"]?so:(originally sent by ${ORIG_VM_CALLERID} on ${ORIG_VM_DATE})\nso)} you might want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n' 51 | emaildateformat: '%A, %B %d, %Y at %r' 52 | pagerdateformat: '%A, %B %d, %Y at %r' 53 | sendvoicemail: 'yes' 54 | asterisk::extensions_general: 55 | static: 'yes' 56 | writeprotect: 'no' 57 | clearglobalvars: 'no' 58 | asterisk::extensions_globals: {} 59 | asterisk::agents_global: {} 60 | # defines the default parkinglot 61 | asterisk::features_general: 62 | parkext: '700' 63 | parkpos: '701-720' 64 | context: 'parkedcalls' 65 | asterisk::features_featuremap: {} 66 | asterisk::features_applicationmap: {} 67 | asterisk::logger_general: {} 68 | asterisk::log_files: 69 | console: 70 | levels: 71 | - 'notice' 72 | - 'warning' 73 | - 'error' 74 | messages: 75 | levels: 76 | - 'notice' 77 | - 'warning' 78 | - 'error' 79 | asterisk::queues_general: 80 | persistentmembers: 'yes' 81 | monitor-type: 'MixMonitor' 82 | asterisk::modules_autoload: true 83 | asterisk::modules_preload: [] 84 | asterisk::modules_noload: 85 | - 'pbx_gtkconsole.so' 86 | - 'pbx_kdeconsole.so' 87 | - 'app_intercom.so' 88 | - 'chan_modem.so' 89 | - 'chan_modem_aopen.so' 90 | - 'chan_modem_bestdata.so' 91 | - 'chan_modem_i4l.so' 92 | - 'chan_capi.so' 93 | - 'chan_alsa.so' 94 | - 'chan_console.so' 95 | - 'chan_oss.so' 96 | - 'cdr_sqlite.so' 97 | - 'app_directory_odbc.so' 98 | - 'res_config_odbc.so' 99 | - 'res_config_pgsql.so' 100 | asterisk::modules_load: 101 | - 'res_musiconhold.so' 102 | asterisk::modules_global: {} 103 | asterisk::manager_enable: true 104 | asterisk::manager_port: 5038 105 | asterisk::manager_bindaddr: '127.0.0.1' 106 | # resources created by create_resources. none by default 107 | asterisk::iax_contexts: {} 108 | asterisk::iax_registries: {} 109 | asterisk::sip_peers: {} 110 | asterisk::sip_registries: {} 111 | asterisk::voicemails: {} 112 | asterisk::extension_contexts: {} 113 | asterisk::agents: {} 114 | asterisk::features: {} 115 | asterisk::queues: {} 116 | asterisk::manager_accounts: {} 117 | -------------------------------------------------------------------------------- /hiera.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 5 3 | hierarchy: 4 | - name: "common" 5 | path: "common.yaml" 6 | -------------------------------------------------------------------------------- /manifests/agent.pp: -------------------------------------------------------------------------------- 1 | # @summary Configure an asterisk agent 2 | # 3 | # @example Basic agent 4 | # asterisk::agent { 'provocateur': 5 | # ext => '700', 6 | # password => Sensitive.new('supersecret'), 7 | # agent_name => 'provocateur', 8 | # } 9 | # 10 | # @see https://www.voip-info.org/asterisk-cmd-agentlogin Dynamic agent login 11 | # @see https://www.voip-info.org/asterisk-cmd-addqueuemember Adding agents to queues 12 | # @see https://www.voip-info.org/asterisk-cmd-removequeuemember Removing agents from queues 13 | # 14 | # @param ext 15 | # Extension corresponding to the agent. 16 | # @param password 17 | # Login password of the agent. 18 | # @param agent_name 19 | # Name by which the agent is referred to within dialplan. 20 | # @param ensure 21 | # Can be set to absent to remove a given agent. 22 | # @param groups 23 | # List of groups to which the agent is associated. 24 | # 25 | define asterisk::agent ( 26 | String $ext, 27 | Sensitive[String] $password, 28 | String $agent_name, 29 | Stdlib::Ensure::File::File $ensure = file, 30 | Array[String[1]] $groups = [] 31 | ) { 32 | $agent_variables = { 33 | groups => $groups, 34 | ext => $ext, 35 | password => $password, 36 | agent_name => $agent_name, 37 | } 38 | asterisk::dotd::file { "agent_${name}.conf": 39 | ensure => $ensure, 40 | dotd_dir => 'agents.d', 41 | content => epp('asterisk/snippet/agent.epp', $agent_variables), 42 | filename => "${name}.conf", 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /manifests/config.pp: -------------------------------------------------------------------------------- 1 | # @summary asterisk basic configuration files. 2 | # 3 | # This class is not intended to be used directly. 4 | # 5 | # @api private 6 | # 7 | class asterisk::config { 8 | assert_private() 9 | 10 | file { $asterisk::confdir: 11 | ensure => directory, 12 | owner => 'asterisk', 13 | group => 'asterisk', 14 | mode => '0755', 15 | } 16 | 17 | if $asterisk::purge_confdir { 18 | File[$asterisk::confdir] { 19 | purge => true, 20 | recurse => true, 21 | } 22 | } 23 | 24 | $cf_with_directory = [ 25 | 'iax', 26 | 'sip', 27 | 'voicemail', 28 | 'extensions', 29 | 'agents', 30 | 'features', 31 | 'queues', 32 | 'manager', 33 | ] 34 | $directories = $cf_with_directory + ['iax.registry', 'sip.registry'] 35 | 36 | $directories.each |String $dir| { 37 | file { "${asterisk::confdir}/${dir}.d": 38 | ensure => directory, 39 | owner => 'asterisk', 40 | group => 'asterisk', 41 | mode => '0750', 42 | } 43 | 44 | # lint:ignore:140chars 45 | # Avoid error messages 46 | # [Nov 19 16:09:48] ERROR[3364] config.c: ********************************************************* 47 | # [Nov 19 16:09:48] ERROR[3364] config.c: *********** YOU SHOULD REALLY READ THIS ERROR *********** 48 | # [Nov 19 16:09:48] ERROR[3364] config.c: Future versions of Asterisk will treat a #include of a file that does not exist as an error, and will fail to load that configuration file. Please ensure that the file '/etc/asterisk/iax.conf.d/*.conf' exists, even if it is empty. 49 | # lint:endignore 50 | file { "${asterisk::confdir}/${dir}.d/null.conf": 51 | ensure => file, 52 | owner => 'asterisk', 53 | group => 'asterisk', 54 | mode => '0640', 55 | content => '', 56 | } 57 | } 58 | 59 | # Options for the logfiles configuration file need some special per-line 60 | # formatting. This creates one formatted string value for each config line 61 | # and returns a hash with the string values instead of the sub-hash. 62 | $formatted_logfiles = $asterisk::log_files.map |$section, $options| { 63 | if $options['formatter'] !~ Undef { 64 | $formatter = "[${options['formatter']}]" 65 | } 66 | else { 67 | $formatter = '' 68 | } 69 | 70 | $return_value = { 71 | $section => "${formatter}${options['levels'].join(',')}", 72 | } 73 | }.reduce({}) |$result, $value| { $result + $value } 74 | 75 | $configs_with_registry = ['iax', 'sip'] 76 | $config_sections = { 77 | iax => { 78 | general => { 79 | delimiter => '=', 80 | options => $asterisk::iax_general, 81 | }, 82 | }, 83 | sip => { 84 | general => { 85 | delimiter => '=', 86 | options => $asterisk::sip_general, 87 | }, 88 | }, 89 | voicemail => { 90 | general => { 91 | delimiter => '=', 92 | options => $asterisk::voicemail_general, 93 | }, 94 | }, 95 | extensions => { 96 | general => { 97 | delimiter => '=', 98 | options => $asterisk::extensions_general, 99 | }, 100 | globals => { 101 | delimiter => '=', 102 | options => $asterisk::extensions_globals, 103 | }, 104 | }, 105 | agents => { 106 | general => { 107 | delimiter => '=', 108 | options => {}, 109 | }, 110 | agents => { 111 | delimiter => '=', 112 | options => $asterisk::agents_global, 113 | }, 114 | }, 115 | features => { 116 | general => { 117 | delimiter => '=', 118 | options => $asterisk::features_general, 119 | }, 120 | featuremap => { 121 | delimiter => ' => ', 122 | options => $asterisk::features_featuremap, 123 | }, 124 | applicationmap => { 125 | delimiter => ' => ', 126 | options => $asterisk::features_applicationmap, 127 | }, 128 | }, 129 | queues => { 130 | general => { 131 | delimiter => '=', 132 | options => $asterisk::queues_general, 133 | }, 134 | }, 135 | logger => { 136 | general => { 137 | delimiter => '=', 138 | options => $asterisk::logger_general, 139 | }, 140 | logfiles => { 141 | delimiter => ' => ', 142 | options => $formatted_logfiles, 143 | }, 144 | }, 145 | manager => { 146 | general => { 147 | delimiter => '=', 148 | options => { 149 | enabled => $asterisk::manager_enable, 150 | port => $asterisk::manager_port, 151 | bindaddr => $asterisk::manager_bindaddr, 152 | }, 153 | }, 154 | }, 155 | modules => { 156 | modules => { 157 | delimiter => ' => ', 158 | # Asterisk's config format is really weird. It looks like ini file but 159 | # it's not exactly that, and it can sometimes (like in this case) mix 160 | # up two types of option delimiters in the same section. The value in 161 | # oddball_options use '=' instead of ' => ' 162 | oddball_delimiter => '=', 163 | oddball_options => { 164 | autoload => bool2str($asterisk::modules_autoload, 'yes', 'no'), 165 | }, 166 | options => { 167 | preload => $asterisk::modules_preload, 168 | load => $asterisk::modules_load, 169 | noload => $asterisk::modules_noload, 170 | }, 171 | }, 172 | global => { 173 | delimiter => '=', 174 | options => $asterisk::modules_global, 175 | }, 176 | }, 177 | } 178 | 179 | $config_files = $cf_with_directory + [ 180 | 'logger', 181 | 'modules', 182 | ] 183 | $config_files.each |String $filename| { 184 | if $filename in $cf_with_directory { 185 | $main_cf_dir = ["${filename}.d"] 186 | } 187 | else { 188 | $main_cf_dir = [] 189 | } 190 | 191 | if $filename in $configs_with_registry { 192 | $cf_directories = $main_cf_dir + ["${filename}.registry.d"] 193 | } else { 194 | $cf_directories = $main_cf_dir 195 | } 196 | 197 | $template_variables = { 198 | config_name => $filename, 199 | include_dirs => $cf_directories, 200 | sections => $config_sections[$filename], 201 | } 202 | file { "${asterisk::confdir}/${filename}.conf": 203 | ensure => file, 204 | owner => 'asterisk', 205 | group => 'asterisk', 206 | mode => '0640', 207 | content => epp('asterisk/config_file.conf.epp', $template_variables), 208 | } 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /manifests/dahdi.pp: -------------------------------------------------------------------------------- 1 | # @summary Requirements for the asterisk dahdi module to work 2 | # 3 | # DAHDI (Digium/Asterisk Hardware Device Interface) lets you connect your 4 | # Asterisk PBX to a card, Digium and some other models, that bridges calls with 5 | # the POTS. 6 | # 7 | # @see https://wiki.asterisk.org/wiki/display/DAHDI/DAHDI 8 | # 9 | # @see https://wiki.asterisk.org/wiki/display/AST/chan_dahdi+Channel+Variables 10 | # 11 | # @todo This class could be merged into config.pp and used conditionally to a 12 | # boolean parameter that enables/disables (off by default) dahdi. 13 | # 14 | # @todo The module would also need to template out chan_dahdi.conf -- changes 15 | # to that file need to trigger a full restart of asterisk, not just a reload. 16 | # 17 | class asterisk::dahdi { 18 | package { [ 19 | 'asterisk-dahdi', 20 | 'dahdi', 21 | 'dahdi-dkms', # dahdi autokompile ubuntu 22 | 'dahdi-linux', # dahdi linux kernel module 23 | 'dahdi-source', # dahdi sources 24 | ]: 25 | ensure => installed, 26 | } 27 | 28 | # User['asterisk'] { 29 | # groups => 'dialout', 30 | # } 31 | } 32 | -------------------------------------------------------------------------------- /manifests/dotd/file.pp: -------------------------------------------------------------------------------- 1 | # @summary Create a file inside a .d directory and set its permissions correctly. 2 | # 3 | # This defined type is not intended to be used directly. 4 | # 5 | # @api private 6 | # 7 | # @param dotd_dir 8 | # Path of the .d directory, relative to asterisk's configuration directory, 9 | # in which the file should be created. 10 | # @param ensure 11 | # Set to `absent` to remove the file 12 | # @param source 13 | # Puppet file source where the contents can be found. 14 | # @param content 15 | # Textual contents of the file. This option is mutually exclusive with 16 | # `$source`. 17 | # @param filename 18 | # Can be used to override the name of the file created. Otherwise, `$name` is 19 | # used as the file name. 20 | # 21 | define asterisk::dotd::file ( 22 | String $dotd_dir, 23 | Stdlib::Ensure::File::File $ensure = file, 24 | Optional[String] $content = undef, 25 | Optional[Stdlib::Filesource] $source = undef, 26 | String $filename = $name, 27 | ) { 28 | assert_private() 29 | 30 | include asterisk::config 31 | include asterisk::service 32 | 33 | $nb_set = count([$content, $source]) 34 | if $nb_set == 0 { 35 | fail('One of $content or $source need to be defined, none were set') 36 | } 37 | if $nb_set == 2 { 38 | fail('Please provide either a $source or a $content, but not both.') 39 | } 40 | 41 | file { "/etc/asterisk/${dotd_dir}/${filename}": 42 | ensure => $ensure, 43 | owner => 'root', 44 | group => 'asterisk', 45 | mode => '0640', 46 | require => Class['asterisk::config'], 47 | notify => Class['asterisk::service'], 48 | } 49 | 50 | if $content =~ String { 51 | File["/etc/asterisk/${dotd_dir}/${filename}"] { 52 | content => $content, 53 | } 54 | } else { 55 | File["/etc/asterisk/${dotd_dir}/${filename}"] { 56 | source => $source, 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /manifests/extensions.pp: -------------------------------------------------------------------------------- 1 | # @summary Configure a dialplan context and extensions within that context 2 | # 3 | # This can be used to configure your different contexts with extensions, but it 4 | # can also be used to create macros that can be called in other contexts. 5 | # 6 | # @example basic context with one extension 7 | # asterisk::extensions { 'basic': 8 | # content => 'exten => 666,1,Hangup()', 9 | # } 10 | # 11 | # @see https://www.voip-info.org/asterisk-config-extensionsconf/ 12 | # @see http://asteriskdocs.org/en/3rd_Edition/asterisk-book-html-chunk/asterisk-DP-Basics.html 13 | # 14 | # @param ensure 15 | # Set this to false to remove the corresponding configuration file. 16 | # @param source 17 | # Puppet file source where the contents of the file can be found. 18 | # @param content 19 | # Textual contents of the file. This option is mutually exclusive with 20 | # `$source`. 21 | # 22 | define asterisk::extensions ( 23 | Stdlib::Ensure::File::File $ensure = file, 24 | Optional[Stdlib::Filesource] $source = undef, 25 | # Only enforcing type for this param since we're using its value 26 | Optional[String] $content = undef, 27 | ) { 28 | if $content !~ Undef { 29 | $real_content = "[${name}]\n${content}" 30 | } 31 | else { 32 | $real_content = $content 33 | } 34 | 35 | asterisk::dotd::file { "extensions_${name}.conf": 36 | ensure => $ensure, 37 | dotd_dir => 'extensions.d', 38 | source => $source, 39 | content => $real_content, 40 | filename => "${name}.conf", 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /manifests/feature.pp: -------------------------------------------------------------------------------- 1 | # @summary Configure an asterisk feature application map grouping 2 | # 3 | # This resource will define an application map grouping. It can be used to set 4 | # dynamic features with the DYNAMIC_FEATURES variable: instead of listing all 5 | # of the application maps that need to be enabled in DYNAMIC_FEATURES, you can 6 | # use the name of a group to enable them all. 7 | # 8 | # To configure global features, see the `features_general` parameter to the 9 | # main class, `asterisk`. 10 | # 11 | # @example feature configuration 12 | # asterisk::feature { 'shifteight': 13 | # options => { 14 | # unpauseMonitor => '*1', 15 | # pauseMonitor => '*2', 16 | # } 17 | # } 18 | # 19 | # @see http://asteriskdocs.org/en/3rd_Edition/asterisk-book-html-chunk/AdditionalConfig_id256654.html#AdditionalConfig_id256980 20 | # @see https://www.voip-info.org/asterisk-config-featuresconf/ 21 | # 22 | # @todo list specific options as params instead of using an options hash 23 | # 24 | # @param options 25 | # Hash of options with keys being option names and values their values. 26 | # @param ensure 27 | # Set this to `absent` to remove the feature. 28 | # 29 | define asterisk::feature ( 30 | Hash $options, 31 | Stdlib::Ensure::File::File $ensure = file, 32 | ) { 33 | $feature_variables = { 34 | context => $name, 35 | options => $options, 36 | } 37 | asterisk::dotd::file { "featuremap_group_${name}.conf": 38 | ensure => $ensure, 39 | dotd_dir => 'features.d', 40 | content => epp('asterisk/snippet/feature.epp', $feature_variables), 41 | filename => "${name}.conf", 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /manifests/iax.pp: -------------------------------------------------------------------------------- 1 | # @summary Configure an IAX2 context and its options 2 | # 3 | # A context named after `$name` will be created. You can configure iax2 users, 4 | # peers or the special context `callnumberlimits` that lets you override limits 5 | # to call numbers per IP address range. 6 | # 7 | # @see https://www.voip-info.org/asterisk-config-iaxconf/ 8 | # 9 | # @todo list all options as parameters instead of using textual contents 10 | # 11 | # @param ensure 12 | # Set this to `absent` to remove the configuration file. 13 | # @param source 14 | # Puppet file source where the contents of the file can be found. 15 | # @param content 16 | # Textual contents of the file being created. This option is mutually 17 | # exclusive with `$source`. The content is placed after the name of the 18 | # context (which is `$name`) and so it should not include the context name 19 | # definition. 20 | # 21 | define asterisk::iax ( 22 | Stdlib::Ensure::File::File $ensure = file, 23 | Optional[Stdlib::Filesource] $source = undef, 24 | # Only enforcing type for this param since we're using its value 25 | Optional[String] $content = undef 26 | ) { 27 | if $content !~ Undef { 28 | $real_content = "[${name}]\n${content}" 29 | } 30 | else { 31 | $real_content = $content 32 | } 33 | 34 | asterisk::dotd::file { "iax_${name}.conf": 35 | ensure => $ensure, 36 | dotd_dir => 'iax.d', 37 | source => $source, 38 | content => $real_content, 39 | filename => "${name}.conf", 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /manifests/init.pp: -------------------------------------------------------------------------------- 1 | # @summary Install and configure an asterisk server. 2 | # 3 | # @example simple install 4 | # class { 'asterisk': } 5 | # 6 | # @see https://wiki.asterisk.org/wiki/display/AST/Asterisk+Queues 7 | # 8 | # @todo make it possible to manage dialplan with the two other methods (e.g. 9 | # AEL and Lua) 10 | # @todo overhaul README file before release. lots of things have changed 11 | # @todo write spec tests for all the code 12 | # @todo manage pjsip.conf 13 | # @todo manage cdr*.conf 14 | # @todo manage musiconhold.conf 15 | # 16 | # @param manage_service 17 | # Set this to false to avoid managing the asterisk service. By default puppet 18 | # will enable the service and ensure that it is running. 19 | # @param manage_package 20 | # Set this to false to avoid installing the asterisk package. 21 | # @param package_name 22 | # Name or array of the package(s) being installed for asterisk. 23 | # @param service_name 24 | # Name of the asterisk service. 25 | # @param confdir 26 | # Absolute path to the asterisk configuration directory. 27 | # @param purge_confdir 28 | # Set this to true to enable autoremoval of configuration files that are 29 | # not managed by puppet inside of asterisk's `confdir`. 30 | # 31 | # @param iax_general 32 | # Global configurations for IAX2. Options are set in the file as `key = 33 | # value` in the `[general]` section of `iax.conf`. 34 | # @param iax_contexts 35 | # Hash of resource_name => params used to instantiate `asterisk::iax` 36 | # defined types. 37 | # @param iax_registries 38 | # Hash of resource_name => params used to instantiate 39 | # `asterisk::registry::iax` defined types. 40 | # @param sip_general 41 | # Global configurations for SIP. Options are set in the file as `key = value` 42 | # in the `[general]` section of the `sip.conf` file. 43 | # @param sip_peers 44 | # Hash of resource_name => params used to instantiate `asterisk::sip` 45 | # defined types. 46 | # @param sip_registries 47 | # Hash of resource_name => params used to instantiate 48 | # `asterisk::registry::sip` defined types. 49 | # @param voicemail_general 50 | # Global configurations for voicemail. Options are set in the file as `key = 51 | # value` in the `[general]` section of the `voicemail.conf` file. 52 | # @param voicemails 53 | # Hash of resource_name => params used to instantiate `asterisk::voicemail` 54 | # defined types. 55 | # @param extensions_general 56 | # Global configurations for the dialplan. Options are set in the file as `key 57 | # = value` in the `[general]` section of the `extensions.conf` file. 58 | # @param extensions_globals 59 | # Hash of global variables for the dialplan, placed in the `[globals]` 60 | # section of the `extensions.conf` file. 61 | # 62 | # WARNING: If you load any other extension configuration engine, such as 63 | # pbx_ael.so, your global variables may be overridden by that file. Please 64 | # take care to use only one location to set global variables, and you will 65 | # likely save yourself a ton of grief. 66 | # 67 | # The variables defined here can be accessed throughout the dialplan with the 68 | # `GLOBAL()` function. Global variables can make dialplans reusable by 69 | # different servers with different use cases. 70 | # 71 | # They also make dialplans easier to maintain by concentrating certain 72 | # information in one location (e.g. to avoid having to modify the same value 73 | # through many contexts and macros). 74 | # 75 | # Global variables can also be used for hiding passwords from Asterisk logs, 76 | # for example for `register` lines or calls to `Dial()` where information 77 | # about the provider is combined with username and password: when using a 78 | # global variable, the variable name will be shown in logs, not the actual 79 | # password. 80 | # 81 | # Variables are set in the file as `key=value`. If you pass in a Sensitive 82 | # type as the value, it will be unwrapped for outputting in the configuration 83 | # file: this can avoid showing certain sensitive information (as passwords) 84 | # in puppet logs. 85 | # @param extension_contexts 86 | # Hash of resource_name => params used to instantiate `asterisk::extension` 87 | # defined types. 88 | # @param agents_global 89 | # Global configurations for agents. Options are set in the file as `key = 90 | # value` in the `[agents]` section of the `agents.conf` file. 91 | # @param agents 92 | # Hash of resource_name => params used to instantiate `asterisk::agent` 93 | # defined types. 94 | # @param features_general 95 | # Global call features. Options are set in the file as `key = value` in the 96 | # `[general]` section of `features.conf`. 97 | # @param features_featuremap 98 | # Global feature maps. Options are set in the file as `key => value` in the 99 | # `[featuremap]` section of `features.conf`. 100 | # @param features_applicationmap 101 | # Global application feature maps. Options are set in the file as 102 | # `key => value` in the `[applicationmap]` section of `features.conf`. 103 | # @param features 104 | # Hash of resource_name => params used to instantiate `asterisk::feature` 105 | # defined types. 106 | # @param logger_general 107 | # Global configurations for asterisk logging. Options are set in the file as 108 | # `key=value` in the `[general]` section of `logger.conf`. 109 | # @param log_files 110 | # A hash defining log files. 111 | # 112 | # Top-level keys set log file names. 113 | # 114 | # Log files can use the special names `console` or `syslog` to determine 115 | # what output is sent to the asterisk CLI console and syslog, respectively. 116 | # 117 | # All other top-level keys represent a file name. File names can 118 | # be either relative to the `asterisk.conf` setting `astlogdir` or an 119 | # absolute path. 120 | # 121 | # Values associated to the top-level keys should be a hash that 122 | # contains at least one key, `levels`. The value for `levels` should be an 123 | # array listing logging levels for this log file. 124 | # 125 | # As well as `levels`, there can be an optional key, `formatter`. Its value 126 | # should be a string containing either `default` or `json` and it defines 127 | # which format will be output to the log. If the `formatter` key is 128 | # omitted, asterisk's default log format is used. 129 | # @param queues_general 130 | # Global configurations for queues. Options are set in the file as 131 | # `key => value` in the `[general]` section of the `queues.conf` file. 132 | # @param queues 133 | # Hash of resource_name => params used to instantiate `asterisk::queue` 134 | # defined types. 135 | # @param modules_autoload 136 | # Set this to false to avoid having asterisk load modules automatically on an 137 | # as-needed basis. This can be used to configure modules in a more 138 | # restrictive manner. 139 | # @param modules_preload 140 | # List of modules that asterisk should load before asterisk core has been 141 | # initialized. This can be useful if you wish to map all module configuration 142 | # files into Realtime storage. 143 | # @param modules_noload 144 | # List of modules that asterisk should not load. This can be useful if 145 | # `modules_autoload` is set to `true`. 146 | # @param modules_load 147 | # List of modules that asterisk should load on startup. This is useful if 148 | # you've set `modules_autoload` to `false`. 149 | # @param modules_global 150 | # Global configurations for modules. Options are set in the file as 151 | # `key => value` in the `[global]` section of the `modules.conf` file. 152 | # @param manager_enable 153 | # Set this to false to disable asterisk manager. 154 | # @param manager_port 155 | # Port number on which asterisk will listen to for manager connections. 156 | # Defaults to 5038. 157 | # @param manager_bindaddr 158 | # IP address to have asterisk bind to for manager connections. Defaults to 159 | # binding to localhost. 160 | # @param manager_accounts 161 | # Hash of resource_name => params used to instantiate `asterisk::manager` 162 | # defined types. 163 | # 164 | class asterisk ( 165 | # Global management options 166 | Boolean $manage_service, 167 | Boolean $manage_package, 168 | Variant[String, Array[String]] $package_name, 169 | String $service_name, 170 | Stdlib::Absolutepath $confdir, 171 | Boolean $purge_confdir, 172 | # Asterisk modules and applications 173 | Hash $iax_general, 174 | Stdlib::CreateResources $iax_contexts, 175 | Stdlib::CreateResources $iax_registries, 176 | Hash $sip_general, 177 | Stdlib::CreateResources $sip_peers, 178 | Stdlib::CreateResources $sip_registries, 179 | Hash $voicemail_general, 180 | Stdlib::CreateResources $voicemails, 181 | Hash $extensions_general, 182 | Asterisk::ExtGlobalVars $extensions_globals, 183 | Stdlib::CreateResources $extension_contexts, 184 | Hash $agents_global, 185 | Stdlib::CreateResources $agents, 186 | Asterisk::FeaturesGeneral $features_general, 187 | Asterisk::Featuremap $features_featuremap, 188 | Hash[String,String] $features_applicationmap, 189 | Stdlib::CreateResources $features, 190 | Hash[String,String] $logger_general, 191 | Hash[String,Asterisk::Logfile] $log_files, 192 | Hash $queues_general, 193 | Stdlib::CreateResources $queues, 194 | Boolean $modules_autoload, 195 | Array[String] $modules_preload, 196 | Array[String] $modules_noload, 197 | Array[String] $modules_load, 198 | Hash $modules_global, 199 | Boolean $manager_enable, 200 | Integer $manager_port, 201 | String $manager_bindaddr, 202 | Stdlib::CreateResources $manager_accounts, 203 | ) { 204 | # We'll only ensure the type of some of the *_general on which templates 205 | # iterate. There's no complex data type that can let us be this flexible 206 | # (e.g. everything should be a string, but those handful of keys. 207 | assert_type(Array[String], $iax_general['allow']) 208 | assert_type(Array[String], $iax_general['disallow']) 209 | 210 | assert_type(Array[String], $sip_general['allow']) 211 | assert_type(Array[String], $sip_general['disallow']) 212 | assert_type(Array[String], $sip_general['domain']) 213 | assert_type(Array[String], $sip_general['localnet']) 214 | 215 | contain asterisk::install 216 | contain asterisk::config 217 | contain asterisk::service 218 | 219 | # create_resources: 220 | create_resources('asterisk::iax', $iax_contexts) 221 | create_resources('asterisk::registry::iax', $iax_registries) 222 | create_resources('asterisk::sip', $sip_peers) 223 | create_resources('asterisk::registry::sip', $sip_registries) 224 | create_resources('asterisk::voicemail', $voicemails) 225 | create_resources('asterisk::extension', $extension_contexts) 226 | create_resources('asterisk::agent', $agents) 227 | create_resources('asterisk::feature', $features) 228 | create_resources('asterisk::queue', $queues) 229 | create_resources('asterisk::manager', $manager_accounts) 230 | 231 | Class['asterisk::install'] 232 | -> Class['asterisk::config'] 233 | ~> Class['asterisk::service'] 234 | } 235 | -------------------------------------------------------------------------------- /manifests/install.pp: -------------------------------------------------------------------------------- 1 | # @summary Install packages that are necessary for an asterisk server. 2 | # 3 | # This class is not intended to be used directly. 4 | # 5 | # @api private 6 | # 7 | class asterisk::install { 8 | assert_private() 9 | 10 | if $asterisk::manage_package { 11 | package { $asterisk::package_name: 12 | ensure => installed, 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /manifests/language.pp: -------------------------------------------------------------------------------- 1 | # @summary Install an asterisk language pack. 2 | # 3 | # The name of the resource is the name of a language pack. 4 | # 5 | # The language packs defined here were taken directly from packages available 6 | # on debian and so this might not work for other distros. 7 | # 8 | # @example installing two language packs 9 | # asterisk::language { ['de', 'es']: } 10 | # 11 | define asterisk::language { 12 | $allowed_languages = [ 13 | 'de', 14 | 'es-co', 15 | 'fr-armelle', 16 | 'fr-proformatique', 17 | 'it-menardi', 18 | 'it-menardi-alaw', 19 | 'it-menardi-gsm', 20 | 'it-menardi-wav', 21 | 'se', 22 | 'es', 23 | ] 24 | $allowed_core_languages = [ 25 | 'core-sounds-en', 26 | 'core-sounds-en-g722', 27 | 'core-sounds-en-gsm', 28 | 'core-sounds-en-wav', 29 | 'core-sounds-es', 30 | 'core-sounds-es-g722', 31 | 'core-sounds-es-gsm', 32 | 'core-sounds-es-wav', 33 | 'core-sounds-fr', 34 | 'core-sounds-fr-g722', 35 | 'core-sounds-fr-gsm', 36 | 'core-sounds-fr-wav', 37 | 'core-sounds-ru', 38 | 'core-sounds-ru-g722', 39 | 'core-sounds-ru-gsm', 40 | 'core-sounds-ru-wav', 41 | ] 42 | 43 | if !($name in $allowed_languages) and !($name in $allowed_core_languages) { 44 | fail("Language '${name}' for Asterisk is unsupported.") 45 | } 46 | 47 | if ($name in $allowed_core_languages) { 48 | package { "asterisk-${name}": ensure => installed; } 49 | } 50 | else { 51 | package { "asterisk-prompt-${name}": ensure => installed; } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /manifests/manager.pp: -------------------------------------------------------------------------------- 1 | # @summary Configure an asterisk manager 2 | # 3 | # @example manager with default authorizations that can connect from LAN. 4 | # asterisk::manager { 'sophie': 5 | # secret => Sensitive.new('youllneverguesswhatitis'), 6 | # permit => ['192.168.120.0/255.255.255.0'], 7 | # } 8 | # 9 | # @see http://asteriskdocs.org/en/3rd_Edition/asterisk-book-html-chunk/AMI-configuration.html#AMI_id265404 10 | # @see https://www.voip-info.org/asterisk-config-managerconf/ 11 | # 12 | # @param secret 13 | # Authentication password for the manager. 14 | # @param ensure 15 | # Set to `absent` to remove the manager. 16 | # @param manager_name 17 | # Can be used to override the name of the manager. By default the 18 | # name of the manager corresponds to `$name`. 19 | # @param deny 20 | # List of IP specifications that are denied access to the manager. Denied 21 | # IPs can be overridden by `$permit`. This makes it possible to only permit 22 | # access to some IP addresses. Default value is to deny access to everybody. 23 | # @param permit 24 | # List of IP specifications that are permitted access to the manager. 25 | # Defaults to premitting only localhost. 26 | # @param read 27 | # List of authorizations given to the manager to read certain information or 28 | # configuration. Defaults to `system` and `call`. 29 | # @param write 30 | # List of authorizations given to the manager to write (change) certain 31 | # information or configuration. Defaults to `system` and `call`. 32 | # @param writetimeout 33 | # Timeout in milliseconds used by Asterisk when writing data to the AMI 34 | # connection for this user. 35 | # @param displayconnects 36 | # Set this to no to avoid reporting connections to the AMI as verbose 37 | # messages printed to the Asterisk console. 38 | # @param eventfilter 39 | # Whitelist- or blacklist-style filtering of manager events before they are 40 | # delivered to the AMI client application. Filters are specified using a 41 | # regular expression. A specified filter is a whitelist filter unless 42 | # preceded by an exclamation point. 43 | # 44 | define asterisk::manager ( 45 | Sensitive[String[1]] $secret, 46 | Stdlib::Ensure::File::File $ensure = file, 47 | String[1] $manager_name = $name, 48 | Array[String[1]] $deny = ['0.0.0.0/0.0.0.0'], 49 | Array[String[1]] $permit = ['127.0.0.1/255.255.255.255'], 50 | Array[Asterisk::ManagerPerms] $read = ['system', 'call'], 51 | Array[Asterisk::ManagerPerms] $write = ['system', 'call'], 52 | Integer $writetimeout = 100, 53 | Boolean $displayconnects = true, 54 | Optional[String] $eventfilter = undef, 55 | ) { 56 | $wo_rights = ['config','command','originate'] 57 | $wo_rights.each |String $right| { 58 | if $right in $read { 59 | fail("write-only right '${right}' given to the \$read parameter") 60 | } 61 | } 62 | 63 | $ro_rights = ['log','verbose','dtmf','cdr','dialplan','cc'] 64 | $ro_rights.each |String $right| { 65 | if $right in $write { 66 | fail("read-only right '${right}' given to the \$write parameter") 67 | } 68 | } 69 | 70 | $manager_variables = { 71 | manager_name => $manager_name, 72 | secret => $secret, 73 | deny => $deny, 74 | permit => $permit, 75 | read => $read, 76 | write => $write, 77 | writetimeout => $writetimeout, 78 | displayconnects => bool2str($displayconnects, 'yes', 'no'), 79 | eventfilter => $eventfilter, 80 | } 81 | asterisk::dotd::file { "manager_${name}.conf": 82 | ensure => $ensure, 83 | dotd_dir => 'manager.d', 84 | content => epp('asterisk/snippet/manager.epp', $manager_variables), 85 | filename => "${name}.conf", 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /manifests/queue.pp: -------------------------------------------------------------------------------- 1 | # @summary Configure an asterisk queue 2 | # 3 | # This resource presents a multitude of options, corresponding to different 4 | # options that can be configured for queues. 5 | # 6 | # @see http://www.asteriskdocs.org/en/3rd_Edition/asterisk-book-html-chunk/ACD_id288901.html#options_defined_queues Definitions of options 7 | # @see http://www.asteriskdocs.org/en/3rd_Edition/asterisk-book-html-chunk/asterisk-ACD.html 8 | # @see http://www.asteriskdocs.org/en/3rd_Edition/asterisk-book-html-chunk/ACD_id288932.html#ACD_id36004485 Changing penalties dynamically 9 | # 10 | # @example create a queue with 10 max callers and strategy `random` 11 | # asterisk::queue { 'shortq': 12 | # stragegy => 'random', 13 | # maxlen => 10, 14 | # } 15 | # 16 | # @todo use better data types. some params should be boolean. some should have an enum. 17 | # 18 | # @param ensure 19 | # Set this to `absent` in order to remove a queue. 20 | # 21 | # @param strategy 22 | # Name of the queue strategy that determines which member phones are ringing 23 | # when there is a call in the queue that needs answering. If this parameter 24 | # is not defined, the strategy defaults to 'ringall'. 25 | # @param context 26 | # Name of a dialplan context. Allows a caller to exit the queue by pressing a 27 | # single DTMF digit. If a context is specified and the caller enters a 28 | # number, that digit will attempt to be matched in the context specified, and 29 | # dialplan execution will continue there. 30 | # @param defaultrule 31 | # Associates a queue rule as defined in queuerules.conf to this queue, which 32 | # is used to dynamically change the minimum and maximum penalties, which are 33 | # then used to select an available agent. 34 | # @param maxlen 35 | # Maximum number of allowed callers in the queue. A value of 0 allows an 36 | # unlimited number of callers in the queue. If unspecified, defaults to 0. 37 | # @param musicclass 38 | # Name of a music class as defined in `musiconhold.conf` to be used for this 39 | # particular queue. You can also override this value with the 40 | # CHANNEL(musicclass) channel variable. 41 | # @param servicelevel 42 | # Threshold in seconds for queue waiting time. This can be then used in 43 | # statistics to determine the number of calls that have passed the 44 | # `servicelevel` threshold. 45 | # 46 | # @param members 47 | # List of static members of this queue. Each member should be specified a 48 | # `Technology/Device_ID`. 49 | # @param memberdelay 50 | # Optional number of seconds to add as delay before the caller and member get 51 | # connected to each other. 52 | # @param penaltymemberslimit 53 | # Optional lower bound to start disregarding penalty if number of members in 54 | # the queue is lower than this number. 55 | # @param membermacro 56 | # Name of a macro to be executed just prior to bridging the caller and the 57 | # queue member. 58 | # @param membergosub 59 | # If set, run this gosub when connected to the queue member you can override 60 | # this gosub by setting the gosub option on the queue application 61 | # @param setinterfacevar 62 | # If set to `yes`, the channel variables `MEMBERINTERFACE`, `MEMBERNAME`, 63 | # `MEMBERCALLS`, `MEMBERLASTCALL`, `MEMBERPENALTY`, `MEMBERDYNAMIC` and 64 | # `MEMBERREALTIME` will be set just prior to connecting the caller with the 65 | # queue member. 66 | # @param setqueuevar 67 | # If set to `yes`, the channel variables `QUEUENAME`, `QUEUEMAX`, 68 | # `QUEUESTRATEGY`, `QUEUECALLS`, `QUEUEHOLDTIME`, `QUEUECOMPLETED`, 69 | # `QUEUEABANDONED`, `QUEUESRVLEVEL` and `QUEUESRVLEVELPERF` will be set just 70 | # prior to the call being bridged. 71 | # @param setqueueentryvar 72 | # If set to `yes`, the channel variables `QEHOLDTIME` and `QEORIGINALPOS` 73 | # will be set just prior to the call being bridged. 74 | # @param weight 75 | # The weight of a queue. A queue with a higher weight defined will get first 76 | # priority when members are associated with multiple queues. 77 | # @param reportholdtime 78 | # If set to `yes`, enables reporting of the caller’s hold time to the queue 79 | # member prior to bridging. 80 | # @param ringinuse 81 | # If set to `no`, avoid sending calls to members whose status is `In Use`. 82 | # Only the SIP channel driver is currently able to accurately report this 83 | # status. 84 | # @param wrapuptime 85 | # Number of seconds to keep a member unavailable in a queue after completing 86 | # a call. 87 | # @param timeout 88 | # Number of seconds to ring a member’s device. Also see `timeoutpriority`. 89 | # @param timeoutrestart 90 | # If set to `yes`, resets the timeout for an agent to answer if either a 91 | # `BUSY` or `CONGESTION` status is received from the channel. This can be 92 | # useful if the agent is allowed to reject or cancel a call. 93 | # @param timeoutpriority 94 | # Define which value of `timeout` takes precedence in case of a conflict. Set 95 | # to `conf` to have the value configured with `timeout` on this resource take 96 | # precedence. Defaults to `app`, which means the `timeout` value from the 97 | # `Queue()` application will take precedence. 98 | # @param retry 99 | # Number of seconds to wait before attempting the next member in the queue if 100 | # the `timeout` value is exhausted while attempting to ring a member of the 101 | # queue. 102 | # @param autopause 103 | # Set this to `yes` to enable the automatic pausing of members who fail to 104 | # answer a call. A value of `all` causes this member to be paused in all 105 | # queues they are a member of. 106 | # 107 | # @param joinempty 108 | # Controls whether a caller is added to the queue when no members are 109 | # available. Comma-separated options can be included to define how this 110 | # option determines whether members are available. See reference `Definitions 111 | # of options` to see what possible values this can take and what they mean. 112 | # @param leavewhenempty 113 | # control whether callers are kicked out of the queue when members are no 114 | # longer available to take calls. This can take values similar to 115 | # `joinempty`. 116 | # @param eventwhencalled 117 | # If set to `yes` manager events `AgentCalled`, `AgentDump`, `AgentConnect` 118 | # and `AgentComplete` will be sent to the Asterisk Manager Interface (AMI). 119 | # If set to vars, all channel variables associated with the agent will also 120 | # be sent to the AMI. Defaults to `no`. 121 | # @param eventmemberstatus 122 | # If set to `yes`, the QueueMemberStatus event will be sent to AMI. Note that 123 | # this may generate a lot of manager events. 124 | # @param monitor_type 125 | # If set to `MixMonitor`, the `MixMonitor()` application will be used for 126 | # recording calls within the queue. If not specified, the `Monitor()` 127 | # application will be used instead. This setting applies specifically for 128 | # this queue and overrides the general option with the same name. 129 | # @param monitor_format 130 | # File format to use when recording. If unspecified, calls will not be 131 | # recorded. 132 | # @param autofill 133 | # If set to `no`, the queue application will attempt to deliver calls to 134 | # agents in a serial manner. This means only one call is attempted to be 135 | # distributed to agents at a time. Additional callers are not distributed to 136 | # agents until that caller is connected to an agent. If set to `yes`, callers 137 | # are distributed to available agents simultaneously. This value overrides 138 | # the value from the general section for this particular queue. 139 | # 140 | # @param announce 141 | # Filename of an announcement played to the agent that answered the call, 142 | # typically to let them know what queue the caller is coming from. Useful 143 | # when the agent is in multiple queues, especially when set to auto-answer 144 | # the queue. 145 | # @param announce_frequency 146 | # Number of seconds to wait for before we should announce the caller’s 147 | # position and/or estimated hold time in the queue. Set this value to zero or 148 | # let the parameter unspecified to disable. 149 | # @param min_announce_frequency 150 | # Minimum amount of time, in seconds, that must pass before we announce the 151 | # caller’s position in the queue again. This is used when the caller’s 152 | # position may change frequently, to prevent the caller hearing multiple 153 | # updates in a short period of time. 154 | # @param announce_holdtime 155 | # Set to `yes` to play the estimated hold time along with the periodic 156 | # announcements. If set to `once`, the estimated hold time will be played 157 | # only once. Defaults to `no`. 158 | # @param announce_position 159 | # Set to `yes` to have periodic announcements always mention current position 160 | # in the queue. If set to `limit` announcements will only mention the 161 | # position in the queue if it is within the limit defined by 162 | # `announce_position_limit`. If set to `more`, announcements will only 163 | # mention the position in the queue if it is beyond the number in 164 | # `announce_position_limit`. Defaults to `no`. 165 | # @param announce_position_limit 166 | # Position in the queue that represents a threshold for announcements if 167 | # `announce_position` was set to `limit` or `more`. 168 | # @param announce_round_seconds 169 | # If set to a non-zero value, announcements will mention seconds as well, 170 | # rounded to the value specified in this parameter. 171 | # @param periodic_announce 172 | # List of file names of periodic announcements to be played. Prompts are 173 | # played in the order they are defined. If unset, defaults to 174 | # `queue-periodic-announce`. 175 | # @param periodic_announce_frequency 176 | # Time in seconds between periodic announcements to the caller. 177 | # @param random_periodic_announce 178 | # If set to `yes`, will play the defined periodic announcements in a random 179 | # order. 180 | # @param relative_periodic_announce 181 | # If set to `yes`, the periodic_announce_frequency timer will start from when 182 | # the end of the file being played back is reached, instead of from the 183 | # beginning. Defaults to `no`. 184 | # @param queue_youarenext 185 | # Filename of a prompt to play when caller reaches first position in queue. 186 | # If not defined, will play the default value (“You are now first in line”). 187 | # If set to an empty value, the prompt will not be played at all. 188 | # @param queue_thereare 189 | # Filename of a prompt to play in announcements when mentioning how much 190 | # people are before the caller. If not defined, will play the default value 191 | # (“There are”). If set to an empty value, the prompt will not be played at 192 | # all. 193 | # @param queue_callswaiting 194 | # Filename of a prompt to play in announcements after saying number of calls 195 | # before caller. If not defined, will play the default value (“calls 196 | # waiting”). If set to an empty value, the prompt will not be played at all. 197 | # @param queue_holdtime 198 | # Filename of a prompt to play when starting to announce estimated wait time. 199 | # If not defined, will play the default value (“The current estimated hold 200 | # time is”). If set to an empty value, the prompt will not be played at all. 201 | # @param queue_minute 202 | # Filename of a prompt to play after stating number of estimated minutes, if 203 | # the number is 1. If not defined, will play the default value (“minute”). If 204 | # set to an empty value, the prompt will not be played at all. 205 | # @param queue_minutes 206 | # Filename of a prompt. This is the same as `queue_minute` but for when the 207 | # number of minutes is more than 1. 208 | # @param queue_seconds 209 | # Filename of a prompt to play after stating number of estimated seconds. If 210 | # not defined, will play the default value (“seconds”). If set to an empty 211 | # value, the prompt will not be played at all. 212 | # @param queue_thankyou 213 | # Filename of a prompt. If not defined, will play the default value (“Thank 214 | # you for your patience”). If set to an empty value, the prompt will not be 215 | # played at all. 216 | # @param queue_reporthold 217 | # Filename of a prompt. If not defined, will play the default value (“Hold 218 | # time”). If set to an empty value, the prompt will not be played at all. 219 | # 220 | define asterisk::queue ( 221 | Stdlib::Ensure::File::File $ensure = file, 222 | Optional[String[1]] $strategy = undef, 223 | Array[String[1]] $members = [], 224 | Optional[Integer] $memberdelay = undef, 225 | Optional[String[1]] $penaltymemberslimit = undef, 226 | Optional[String[1]] $membermacro = undef, 227 | Optional[String[1]] $membergosub = undef, 228 | Optional[String[1]] $context = undef, 229 | Optional[String[1]] $defaultrule = undef, 230 | Optional[Integer] $maxlen = undef, 231 | Optional[String[1]] $musicclass = undef, 232 | Optional[String[1]] $servicelevel = undef, 233 | Optional[Integer] $weight = undef, 234 | Array[String[1]] $joinempty = [], 235 | Array[String[1]] $leavewhenempty = [], 236 | Optional[String[1]] $eventwhencalled = undef, 237 | Optional[String[1]] $eventmemberstatus = undef, 238 | Optional[String[1]] $reportholdtime = undef, 239 | Optional[String[1]] $ringinuse = undef, 240 | Optional[String[1]] $monitor_type = undef, 241 | Array[String[1]] $monitor_format = [], 242 | Optional[String[1]] $announce = undef, 243 | Optional[Integer] $announce_frequency = undef, 244 | Optional[Integer] $min_announce_frequency = undef, 245 | Optional[String[1]] $announce_holdtime = undef, 246 | Optional[String[1]] $announce_position = undef, 247 | Optional[Integer] $announce_position_limit = undef, 248 | Optional[Integer] $announce_round_seconds = undef, 249 | Array[String[1]] $periodic_announce = [], 250 | Optional[Integer] $periodic_announce_frequency = undef, 251 | Optional[String[1]] $random_periodic_announce = undef, 252 | Optional[String[1]] $relative_periodic_announce = undef, 253 | Optional[String] $queue_youarenext = undef, 254 | Optional[String] $queue_thereare = undef, 255 | Optional[String] $queue_callswaiting = undef, 256 | Optional[String] $queue_holdtime = undef, 257 | Optional[String] $queue_minute = undef, 258 | Optional[String] $queue_minutes = undef, 259 | Optional[String] $queue_seconds = undef, 260 | Optional[String] $queue_thankyou = undef, 261 | Optional[String] $queue_reporthold = undef, 262 | Optional[Integer] $wrapuptime = undef, 263 | Optional[Integer] $timeout = undef, 264 | Optional[String[1]] $timeoutrestart = undef, 265 | Optional[String[1]] $timeoutpriority = undef, 266 | Optional[String[1]] $retry = undef, 267 | Optional[String[1]] $autofill = undef, 268 | Optional[String[1]] $autopause = undef, 269 | Optional[String[1]] $setinterfacevar = undef, 270 | Optional[String[1]] $setqueuevar = undef, 271 | Optional[String[1]] $setqueueentryvar = undef 272 | ) { 273 | $queue_variables = { 274 | queue_name => $name, 275 | strategy => $strategy, 276 | members => $members, 277 | memberdelay => $memberdelay, 278 | penaltymemberslimit => $penaltymemberslimit, 279 | membermacro => $membermacro, 280 | membergosub => $membergosub, 281 | context => $context, 282 | defaultrule => $defaultrule, 283 | maxlen => $maxlen, 284 | musicclass => $musicclass, 285 | servicelevel => $servicelevel, 286 | weight => $weight, 287 | joinempty => $joinempty, 288 | leavewhenempty => $leavewhenempty, 289 | eventwhencalled => $eventwhencalled, 290 | eventmemberstatus => $eventmemberstatus, 291 | reportholdtime => $reportholdtime, 292 | ringinuse => $ringinuse, 293 | monitor_type => $monitor_type, 294 | monitor_format => $monitor_format, 295 | announce => $announce, 296 | announce_frequency => $announce_frequency, 297 | min_announce_frequency => $min_announce_frequency, 298 | announce_holdtime => $announce_holdtime, 299 | announce_position => $announce_position, 300 | announce_position_limit => $announce_position_limit, 301 | announce_round_seconds => $announce_round_seconds, 302 | periodic_announce => $periodic_announce, 303 | periodic_announce_frequency => $periodic_announce_frequency, 304 | random_periodic_announce => $random_periodic_announce, 305 | relative_periodic_announce => $relative_periodic_announce, 306 | queue_youarenext => $queue_youarenext, 307 | queue_thereare => $queue_thereare, 308 | queue_callswaiting => $queue_callswaiting, 309 | queue_holdtime => $queue_holdtime, 310 | queue_minute => $queue_minute, 311 | queue_minutes => $queue_minutes, 312 | queue_seconds => $queue_seconds, 313 | queue_thankyou => $queue_thankyou, 314 | queue_reporthold => $queue_reporthold, 315 | wrapuptime => $wrapuptime, 316 | timeout => $timeout, 317 | timeoutrestart => $timeoutrestart, 318 | timeoutpriority => $timeoutpriority, 319 | retry => $retry, 320 | autofill => $autofill, 321 | autopause => $autopause, 322 | setinterfacevar => $setinterfacevar, 323 | setqueuevar => $setqueuevar, 324 | setqueueentryvar => $setqueueentryvar, 325 | } 326 | asterisk::dotd::file { "queue_${name}.conf": 327 | ensure => $ensure, 328 | dotd_dir => 'queues.d', 329 | content => epp('asterisk/snippet/queue.epp', $queue_variables), 330 | filename => "${name}.conf", 331 | } 332 | } 333 | -------------------------------------------------------------------------------- /manifests/registry/iax.pp: -------------------------------------------------------------------------------- 1 | # @summary Configure an IAX2 registry 2 | # 3 | # This makes it possible to register to an IAX2 peer for authenticated 4 | # connections. 5 | # 6 | # @param server 7 | # Hostname or IP address of the server to which Asterisk should register. 8 | # @param user 9 | # User name used for authenticating with the distant server. 10 | # @param password 11 | # Password used for authenticating. 12 | # @param ensure 13 | # Set to `absent` in order to remove the registry. 14 | # 15 | define asterisk::registry::iax ( 16 | Stdlib::Host $server, 17 | String[1] $user, 18 | Sensitive[String[1]] $password, 19 | Stdlib::Ensure::File::File $ensure = file, 20 | ) { 21 | $iax_variables = { 22 | user => $user, 23 | password => $password, 24 | server => $server, 25 | } 26 | asterisk::dotd::file { "registry__iax_${name}.conf": 27 | ensure => $ensure, 28 | dotd_dir => 'iax.registry.d', 29 | content => epp('asterisk/registry/iax.epp', $iax_variables), 30 | filename => "${name}.conf", 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /manifests/registry/sip.pp: -------------------------------------------------------------------------------- 1 | # @summary Configure a SIP registry 2 | # 3 | # This makes it possible to register to a SIP peer for authenticated 4 | # connections. 5 | # 6 | # @param server 7 | # Hostname or IP address of the server to which Asterisk should register. 8 | # @param user 9 | # User id for the local server. 10 | # @param ensure 11 | # Set to `absent` in order to remove the registry. 12 | # @param password 13 | # Optional password used for authenticating. This is required if our peer 14 | # does not match connections only on IP/port. 15 | # @param authuser 16 | # Optional user name used for authenticating with the remote server. This is 17 | # required if our peer does not match connections only on IP/port. 18 | # @param port 19 | # Numerical port with which a connection will be established to the remote 20 | # server. 21 | # @param extension 22 | # Extension that is used when calls are received from the remote server. When 23 | # not set, extension will be 's'. 24 | # 25 | define asterisk::registry::sip ( 26 | Stdlib::Host $server, 27 | String[1] $user, 28 | Stdlib::Ensure::File::File $ensure = file, 29 | Optional[Sensitive[String[1]]] $password = undef, 30 | Optional[String[1]] $authuser = undef, 31 | Optional[Integer] $port = undef, 32 | Optional[String[1]] $extension = undef 33 | ) { 34 | if $password =~ Undef and $authuser !~ Undef { 35 | fail('authuser was specified but no value was given for password. You need both to authenticate.') 36 | } 37 | 38 | $sip_variables = { 39 | user => $user, 40 | password => $password, 41 | authuser => $authuser, 42 | server => $server, 43 | port => $port, 44 | extension => $extension, 45 | } 46 | asterisk::dotd::file { "registry__sip_${name}.conf": 47 | ensure => $ensure, 48 | dotd_dir => 'sip.registry.d', 49 | content => epp('asterisk/registry/sip.epp', $sip_variables), 50 | filename => "${name}.conf", 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /manifests/service.pp: -------------------------------------------------------------------------------- 1 | # @summary Ensure the Asterisk service is running. 2 | # 3 | # This class is not intended to be used directly. 4 | # 5 | # @api private 6 | # 7 | class asterisk::service { 8 | assert_private() 9 | 10 | if $asterisk::manage_service { 11 | service { $asterisk::service_name: 12 | ensure => running, 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /manifests/sip.pp: -------------------------------------------------------------------------------- 1 | # @summary Configure a SIP peer, a user or a template for the previous. 2 | # 3 | # @note It is generally recommended to avoid assigning hostname to a `sip.conf` 4 | # section like `[provider.com]`. 5 | # @note It is generally recommended to use separate inbound and outbound 6 | # sections for SIP providers (instead of type=friend) if you have calls in 7 | # both directions 8 | # 9 | # @example create sip peer of providerZ 10 | # asterisk::sip { 'providerZ': 11 | # account_type => 'peer', 12 | # disallow => ['all'], 13 | # allow => ['ulaw'], 14 | # host => 'sip-host.local', 15 | # secret => Sensitive.new('callthisasecret'), 16 | # } 17 | # 18 | # @see https://www.voip-info.org/asterisk-config-sipconf/ 19 | # 20 | # @todo use better data types. some should be boolean, some should have an enum 21 | # 22 | # @param ensure 23 | # Set this to `absent` in order to remove SIP configuration. 24 | # @param template_name 25 | # Set this to `!` if you are creating a template. Set this to any name of a 26 | # template section to inherit options from it. 27 | # 28 | # @param account_type 29 | # Define how calls are handled. Roughly, `peer` handles outbound and inbound 30 | # calls matches calls by ip/port. `user` handles only inbound calls and 31 | # matches calls by `authname` and `secret`. `friend` handles both inbound and 32 | # outbound calls where inbound calls are matched by `authname` and `secret` 33 | # (like a `user`) but outbound calls are matched by ip and port like a 34 | # `peer`. 35 | # @param username 36 | # Deprecated option in asterisk. You probably want to use `defaultuser` 37 | # instead. 38 | # @param defaultuser 39 | # Authentication user name. 40 | # @param secret 41 | # Authentication secret for inbound connections. 42 | # @param md5secret 43 | # MD5-Hash of `:==SIP_realm==:` (can be used instead of 44 | # `secret`). Default for authenticating to an Asterisk server when SIP realm 45 | # is not explicitly declared is `:asterisk:`. 46 | # @param remotesecret 47 | # Authentication secret for outbound connections. If this is not set, 48 | # `$secret` is used for outbound connections. 49 | # @param context 50 | # Name of the dialplan context that is used as starting point when an inbound 51 | # call is received through this peer/user. 52 | # @param canreinvite 53 | # Deprecated option in asterisk: was renamed to `directmedia`. Whether or not 54 | # to issue a reinvite to the client unless really necessary. This is used to 55 | # interoperate with some (buggy) hardware that crashes if we reinvite, such 56 | # as the common Cisco ATA 186. Setting this to `nonat` will allow reinvite 57 | # when local, deny reinvite when NAT. Finally setting this to `update` will 58 | # use `UPDATE` instead of `INVITE`. 59 | # @param directmedia 60 | # By default, Asterisk tries to re-invite media streams to an optimal path. 61 | # If there's no reason for Asterisk to stay in the media path, the media will 62 | # be redirected. This does not really work well in the case where Asterisk is 63 | # outside and the clients are on the inside of a NAT. In that case, you want 64 | # to set this parameter to `nonat`. `nonat` will allow media path redirection 65 | # (reinvite) but only when the peer where the media is being sent is known to 66 | # not be behind a NAT (as the RTP core can determine it based on the apparent 67 | # IP address the media arrives from). If you set this parameter to `update`, 68 | # Asterisk will use an `UPDATE` command instead of an `INVITE` command to 69 | # redirect media. `update` can also be combined with `nonat` with the value 70 | # `nonat,update`. 71 | # @param directrtpsetup 72 | # Set this to `true` to enable the new experimental direct RTP setup. This 73 | # sets up the call directly with media peer-2-peer without re-invites. Will 74 | # not work for video and cases where the callee sends RTP payloads and fmtp 75 | # headers in the 200 OK that does not match the callers INVITE. This will 76 | # also fail if directmedia is enabled when the device is actually behind NAT. 77 | # @param directmediadeny 78 | # List of CIDR prefixes (e.g. of the form `prefix/number of bits for mask` -- 79 | # for example `172.16.0.0/16`) that should be denied passing directmedia to 80 | # other peers. You can use this if some of your phones are on IP addresses 81 | # that can not reach each other directly. This way you can force RTP to 82 | # always flow through asterisk in such cases. See also `directmediapermit`. 83 | # @param directmediapermit 84 | # List of CIDR prefixes that should be allowed passing directmedia to other 85 | # peers. See `directmediadeny`. 86 | # @param host 87 | # Set this to `dynamic` to require the device to register itself before 88 | # authenticating. Set to a hostname or IP address to match only for this host 89 | # or IP address. 90 | # @param insecure 91 | # If set to `port`, allow matching of peer by IP address without matching 92 | # port number. If set to `invite`, do not require authentication of incoming 93 | # INVITEs. If set to `no`, all connections will be authenticated regardless 94 | # of port or IP address. Defaults to `no`. 95 | # @param language 96 | # Language code to define prompts for this peer/user. 97 | # @param nat 98 | # Use methods to bypass issues when a phone is behind a NAT. This setting is 99 | # not useful for when the asterisk server is the one behind the NAT. Set this 100 | # to `yes` to ignore the address information in the SIP and SDP headers. Set 101 | # this to `force_rport` fore RFC 3581 behavior and disable symmetric RTP 102 | # support. Set this to `comedia` to enable RFC 3581 behavior if the remote 103 | # side requests it and enables symmetric RTP support. 104 | # @param qualify 105 | # If set to `yes`, the check if client is reachable every `qualifyfreq` 106 | # seconds (defaults to 60 seconds). If set to an integer number, corresponds 107 | # to `yes` and defines the timeout in milliseconds after a check packet is 108 | # sent: when the timeout is reached, a peer is considered offline. Valid only 109 | # with `type` set to `peer`. 110 | # @param vmexten 111 | # Name of dialplan extension to reach mailbox. When unspecified, defaults to 112 | # `asterisk`. Valid only with `type` set to `peer`. 113 | # @param callerid 114 | # Caller ID information used when nothing else is available. When 115 | # unspecified, defaults to `asterisk`. 116 | # @param call_limit 117 | # Number of simultaneous calls through this user/peer. 118 | # @param callgroup 119 | # Call groups for calls to this device. 120 | # @param mailbox 121 | # Voicemail extension (for message waiting indications). Not valid for `type` 122 | # set to `user`. 123 | # @param pickupgroup 124 | # Group that can pickup fellow workers’ calls using `*8` and the `Pickup()` 125 | # application on the `*8` extension. 126 | # @param fromdomain 127 | # Default `From:` domain in SIP messages when acting as a SIP UAC (client). 128 | # @param fromuser 129 | # User to put in `from` instead of `$CALLERID(number)` (overrides the 130 | # callerid) when placing calls _to_ a peer (another SIP proxy). Valid only 131 | # with `type` set to `peer`. 132 | # @param outboundproxy 133 | # SRV name (excluding the _sip._udp prefix), hostname, or IP address of the 134 | # outbound SIP Proxy. Valid only with `type` set to `peer`. 135 | # @param t38pt_udptl 136 | # Enable T.83 Fax support. Set to `yes` to enable T.38 with FEC error 137 | # correction. Additionally, you can add comma-separated options: `redundancy` 138 | # enables redundancy error correction. `none` disables error correction. 139 | # `maxdatagram=NN` overrides the maximum datagram value to NN bytes (useful 140 | # for some problematic cases like Cisco media gateways). 141 | # @param disallow 142 | # List of codecs to disallow for this peer/user. The list can contain `all` to 143 | # disallow all known codecs. If set to `all`, codecs that are present in the 144 | # `allow` list will override this setting, so this can be used to restrict to 145 | # a narrow number of codecs. 146 | # @param allow 147 | # List of codecs to allow for this peer/user. The list can contain `all` to 148 | # allow all known codecs. If set to `all`, codecs in `disallow` will override 149 | # this setting, so this can be used to blacklist only a narrow set of codecs. 150 | # @param dtmfmode 151 | # How the client handles DTMF signalling. Defaults to `rfc2833`. Warning: 152 | # `inband` leads to very high CPU load. 153 | # @param transports 154 | # Accepted transport types for this peer/user. Can be `udp`, `tcp` or both 155 | # with the order defining which is set as default (first value is default). 156 | # @param encryption 157 | # Set to `yes` to offer SRTP encrypted media (and only SRTP encrypted media) 158 | # on outgoing calls to a peer. Calls will fail with `HANGUPCAUSE=58` if the 159 | # peer does not support SRTP. Defaults to `no`. 160 | # @param access 161 | # List of permit/deny rules for CIDR prefixes like `prefix/mask`. Each 162 | # element of the list should be a one element hash that specifies either 163 | # 'permit' or 'deny' as a key and the CIDR prefix as its value. Order 164 | # Matters! – Rules are placed in the configuration file in the same order as 165 | # elements were inserted into the list. The last matching deny/permit rule is 166 | # the one used. If no rule matches, then the connection is permitted. 167 | # @param trustrpid 168 | # If a Remote-Party-ID SIP header should be sent. Defaults to `no`. 169 | # @param sendrpid 170 | # If Remote-Party-ID SIP header should be trusted. Defaults to `no`. 171 | # 172 | define asterisk::sip ( 173 | Stdlib::Ensure::File::File $ensure = file, 174 | # lint:ignore:optional_default 175 | Optional[String[1]] $template_name = undef, 176 | Optional[String[1]] $account_type = 'friend', 177 | Optional[String[1]] $username = undef, 178 | Optional[String[1]] $defaultuser = undef, 179 | Optional[Sensitive[String[1]]] $secret = undef, 180 | Optional[String[1]] $md5secret = undef, 181 | Optional[Sensitive[String[1]]] $remotesecret = undef, 182 | Optional[String[1]] $context = undef, 183 | Optional[String[1]] $canreinvite = undef, 184 | Optional[String[1]] $directmedia = 'no', 185 | Optional[Boolean] $directrtpsetup = true, 186 | Array[String[1]] $directmediadeny = [], 187 | Array[String[1]] $directmediapermit = [], 188 | Optional[String[1]] $host = 'dynamic', 189 | Optional[String[1]] $insecure = 'no', 190 | Optional[String[1]] $language = 'en', 191 | Optional[String[1]] $nat = undef, 192 | Optional[String[1]] $qualify = 'no', 193 | Optional[String[1]] $vmexten = undef, 194 | Optional[String[1]] $callerid = undef, 195 | Optional[Integer] $call_limit = undef, 196 | Optional[String[1]] $callgroup = undef, 197 | Optional[String[1]] $mailbox = undef, 198 | Optional[String[1]] $pickupgroup = undef, 199 | Optional[String[1]] $fromdomain = undef, 200 | Optional[String[1]] $fromuser = undef, 201 | Optional[String[1]] $outboundproxy = undef, 202 | Optional[String[1]] $t38pt_udptl = undef, 203 | Array[String[1]] $disallow = [], 204 | Array[String[1]] $allow = [], 205 | Optional[String[1]] $dtmfmode = undef, 206 | Array[String[1]] $transports = [], 207 | Optional[String] $encryption = undef, 208 | Array[Asterisk::Access] $access = [], 209 | Optional[Enum['yes', 'no']] $trustrpid = undef, 210 | Optional[Enum['yes', 'no', 'pai', 'rpid']] $sendrpid = undef 211 | # lint:endignore 212 | ) { 213 | if $canreinvite !~ Undef { 214 | deprecation(@(DEPRECATED_OPTION) 215 | The option "canreinvite" was deprecated by asterisk and replaced with 216 | directmedia. You should check asterisk documentation and use the new 217 | option instead. 218 | | DEPRECATED_OPTION 219 | ) 220 | } 221 | 222 | if $directrtpsetup =~ Boolean { 223 | $real_directrtpsetup = bool2str($directrtpsetup, 'yes', 'no') 224 | } 225 | else { 226 | $real_directrtpsetup = $directrtpsetup 227 | } 228 | 229 | $sip_variables = { 230 | peer_name => $name, 231 | template_name => $template_name, 232 | account_type => $account_type, 233 | username => $username, 234 | defaultuser => $defaultuser, 235 | secret => $secret, 236 | md5secret => $md5secret, 237 | remotesecret => $remotesecret, 238 | context => $context, 239 | canreinvite => $canreinvite, 240 | directmedia => $directmedia, 241 | directrtpsetup => $directrtpsetup, 242 | directmediadeny => $directmediadeny, 243 | directmediapermit => $directmediapermit, 244 | host => $host, 245 | insecure => $insecure, 246 | language => $language, 247 | nat => $nat, 248 | qualify => $qualify, 249 | vmexten => $vmexten, 250 | callerid => $callerid, 251 | call_limit => $call_limit, 252 | callgroup => $callgroup, 253 | mailbox => $mailbox, 254 | pickupgroup => $pickupgroup, 255 | fromdomain => $fromdomain, 256 | fromuser => $fromuser, 257 | outboundproxy => $outboundproxy, 258 | t38pt_udptl => $t38pt_udptl, 259 | disallow => $disallow, 260 | allow => $allow, 261 | dtmfmode => $dtmfmode, 262 | transports => $transports, 263 | encryption => $encryption, 264 | access => $access, 265 | trustrpid => $trustrpid, 266 | sendrpid => $sendrpid, 267 | } 268 | asterisk::dotd::file { "sip_${name}.conf": 269 | ensure => $ensure, 270 | dotd_dir => 'sip.d', 271 | content => epp('asterisk/snippet/sip.epp', $sip_variables), 272 | filename => "${name}.conf", 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /manifests/voicemail.pp: -------------------------------------------------------------------------------- 1 | # @summary Configure a voicemail 2 | # 3 | # @example voicemail with email address 4 | # asterisk::voicemail { 'taro': 5 | # context => 'support2', 6 | # password => Sensitive.new('557722981749'), 7 | # email => 'taro.suupaa@support.com', 8 | # } 9 | # 10 | # @param context 11 | # Name of the context in which the voicemail is assigned. 12 | # @param password 13 | # Authentication password set for accessing the voicemail. This is usually a 14 | # series of numbers so that phones can dial the password, but it can be a 15 | # textual password as well. 16 | # @param ensure 17 | # Set to `absent` to remove the voicemail. 18 | # @param user_name 19 | # Name assigned to the voicemail, usually the name of the person using it. 20 | # @param email 21 | # Email address to which voicemail message sounds will be sent. 22 | # @param pager_email 23 | # Email address to which a page will be sent upon receiving a voicemail. 24 | # @param options 25 | # Hash containing options that are set for the voicemail. For 26 | # example, a specific timezone can be set on individual voicemails with the 27 | # 'tz' option. Options are set in the file as `key = value`. 28 | # 29 | define asterisk::voicemail ( 30 | String[1] $context, 31 | Sensitive[String[1]] $password, 32 | Stdlib::Ensure::File::File $ensure = file, 33 | Optional[String[1]] $user_name = undef, 34 | Optional[String[1]] $email = undef, 35 | Optional[String[1]] $pager_email = undef, 36 | Hash[String,String] $options = {} 37 | ) { 38 | $voicemail_variables = { 39 | context => $context, 40 | voicemail => $name, 41 | password => $password, 42 | user_name => $user_name, 43 | email => $email, 44 | pager_email => $pager_email, 45 | options => $options, 46 | } 47 | asterisk::dotd::file { "${context}-${name}.conf": 48 | ensure => $ensure, 49 | content => epp('asterisk/snippet/voicemail.epp', $voicemail_variables), 50 | dotd_dir => 'voicemail.d', 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "LeLutin-asterisk", 3 | "version": "2.0.3", 4 | "author": "LeLutin", 5 | "summary": "Install and configure the Asterisk PBX service", 6 | "license": "GPL-3.0+", 7 | "source": "https://github.com/lelutin/puppet-asterisk", 8 | "project_page": "https://github.com/lelutin/puppet-asterisk", 9 | "issues_url": "https://github.com/lelutin/puppet-asterisk/issues", 10 | "dependencies": [ 11 | {"name":"puppetlabs/stdlib","version_requirement":">= 8.5.0"} 12 | ], 13 | "requirements": [ 14 | { 15 | "name": "puppet", 16 | "version_requirement": ">= 6.0.0 < 9.0.0" 17 | } 18 | ], 19 | "operatingsystem_support": [ 20 | { 21 | "operatingsystem": "Debian", 22 | "operatingsystemrelease":[ "10", "11" ] 23 | } 24 | ], 25 | "tags": ["asterisk", "sip", "iax", "PBX", "VoIP"] 26 | } 27 | 28 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base", 5 | ":disableDependencyDashboard" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /spec/classes/init_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | describe 'asterisk' do 3 | let(:title) { 'asterisk' } 4 | let(:facts) do 5 | { 6 | os: { 7 | family: 'Debian', 8 | }, 9 | } 10 | end 11 | 12 | context 'with defaults for all parameters' do 13 | it { is_expected.to contain_class('asterisk') } 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'puppetlabs_spec_helper/module_spec_helper' 2 | require 'rspec-puppet-facts' 3 | -------------------------------------------------------------------------------- /templates/config_file.conf.epp: -------------------------------------------------------------------------------- 1 | ; THIS FILE IS MANAGED BY PUPPET 2 | ; all local modifications will be lost 3 | ; 4 | ; To change values found in this file, see the parameters related to 5 | ; <%= $config_name %> on the asterisk module's main class. 6 | ; 7 | ; To see all comments that document each available option, on Debian 8 | ; systems, refer to /usr/share/doc/asterisk-config/samples 9 | ; 10 | <% 11 | $sections.each |String $sect_name, Hash $section_options| { 12 | -%> 13 | [<%= $sect_name %>] 14 | <% 15 | # Weird case where options in the same section use two different assignment 16 | # delimiters. The weird case comes in first in the config file. 17 | if $section_options['oddball_options'] !~ Undef { 18 | $odb_delimiter = $section_options['oddball_delimiter'] 19 | $section_options['oddball_options'].each |String $odb_opt_name, String $odb_value| { 20 | -%> 21 | <%= $odb_opt_name %><%= $odb_delimiter %><%= $odb_value %> 22 | <% 23 | } 24 | # Add a blank line to the config file to better see the difference in the 25 | # two forms of assignments. 26 | -%> 27 | 28 | <% 29 | } 30 | $delimiter = $section_options['delimiter'] 31 | $section_options['options'].each |String $opt_name, Any $value| { 32 | if $value =~ Array { 33 | $value.each |String $v| { 34 | -%> 35 | <%= $opt_name -%><%= $delimiter %><%= $v %> 36 | <% 37 | } 38 | } 39 | else { 40 | -%> 41 | <%= $opt_name -%><%= $delimiter %><%= $value %> 42 | <% 43 | } 44 | } 45 | -%> 46 | 47 | <% 48 | } 49 | -%> 50 | <% 51 | $include_dirs.each |String $dir_path| { 52 | -%> 53 | #include "<%= $dir_path %>/*.conf" 54 | <% 55 | } 56 | -%> 57 | -------------------------------------------------------------------------------- /templates/registry/iax.epp: -------------------------------------------------------------------------------- 1 | ; THIS FILE IS MANAGED BY PUPPET 2 | ; all local modifications will be lost 3 | register => <%= $user %>:<%= $password.unwrap %>@<%= $server %> 4 | -------------------------------------------------------------------------------- /templates/registry/sip.epp: -------------------------------------------------------------------------------- 1 | ; THIS FILE IS MANAGED BY PUPPET 2 | ; all local modifications will be lost 3 | register => <%= $user %><% if $password { -%>:<%= $password.unwrap %><% if $authuser { -%>:<%= $authuser %><% } } -%>@<%= $server %><% if $port { -%>:<%= $port %><% } if $extension { -%>/<%= $extension %><% } -%> 4 | 5 | -------------------------------------------------------------------------------- /templates/snippet/agent.epp: -------------------------------------------------------------------------------- 1 | <% if ! empty($groups) { -%> 2 | group=<%= $groups.join(",") %> 3 | <% } -%> 4 | agent => <%= $ext %>,<%= $password.unwrap %>,<%= $agent_name %> 5 | <% if ! empty($groups) { -%> 6 | ; Reset group to avoid having an impact on other config files. 7 | group= 8 | <% } -%> 9 | -------------------------------------------------------------------------------- /templates/snippet/feature.epp: -------------------------------------------------------------------------------- 1 | ; THIS FILE IS MANAGED BY PUPPET 2 | ; all local modifications will be lost 3 | [<%= $context %>] 4 | <% $options.map |String $name, String $value| { -%> 5 | <%= $name -%> => <%= $value %> 6 | <% } -%> 7 | -------------------------------------------------------------------------------- /templates/snippet/manager.epp: -------------------------------------------------------------------------------- 1 | ; THIS FILE IS MANAGED BY PUPPET 2 | ; all local modifications will be lost 3 | [<%= $manager_name %>] 4 | secret = <%= $secret.unwrap %> 5 | <% $deny.each |$deny_rule| { -%> 6 | deny = <%= $deny_rule %> 7 | <% } -%> 8 | <% $permit.each |$permit_rule| { -%> 9 | permit = <%= $permit_rule %> 10 | <% } -%> 11 | read = <%= $read.join(",") %> 12 | write = <%= $write.join(",") %> 13 | writetimeout = <%= $writetimeout %> 14 | displayconnects = <%= $displayconnects %> 15 | <% if $eventfilter { -%> 16 | eventfilter = <%= $eventfilter %> 17 | <% } -%> 18 | -------------------------------------------------------------------------------- /templates/snippet/queue.epp: -------------------------------------------------------------------------------- 1 | ; THIS FILE IS MANAGED BY PUPPET 2 | ; all local modifications will be lost 3 | [<%= $queue_name %>] 4 | <% if $strategy { -%> 5 | strategy=<%= $strategy %> 6 | <% } -%> 7 | <% $members.each |String $member| { -%> 8 | member=<%= $member %> 9 | <% } -%> 10 | <% if $memberdelay { -%> 11 | memberdelay=<%= $memberdelay %> 12 | <% } -%> 13 | <% if $penaltymemberslimit { -%> 14 | penaltymemberslimit=<%= $penaltymemberslimit %> 15 | <% } -%> 16 | <% if $membermacro { -%> 17 | membermacro=<%= $membermacro %> 18 | <% } -%> 19 | <% if $membergosub { -%> 20 | membergosub=<%= $membergosub %> 21 | <% } -%> 22 | <% if $context { -%> 23 | context=<%= $context %> 24 | <% } -%> 25 | <% if $defaultrule { -%> 26 | defaultrule=<%= $defaultrule %> 27 | <% } -%> 28 | <% if $maxlen { -%> 29 | maxlen=<%= $maxlen %> 30 | <% } -%> 31 | <% if $musicclass { -%> 32 | musicclass=<%= $musicclass %> 33 | <% } -%> 34 | <% if $servicelevel { -%> 35 | servicelevel=<%= $servicelevel %> 36 | <% } -%> 37 | <% if $weight { -%> 38 | weight=<%= $weight %> 39 | <% } -%> 40 | <% if ! empty($joinempty) { -%> 41 | joinempty=<%= $joinempty.join(',') %> 42 | <% } -%> 43 | <% if ! empty($leavewhenempty) { -%> 44 | leavewhenempty=<%= $leavewhenempty.join(',') %> 45 | <% } -%> 46 | <% if $eventwhencalled { -%> 47 | eventwhencalled=<%= $eventwhencalled %> 48 | <% } -%> 49 | <% if $eventmemberstatus { -%> 50 | eventmemberstatus=<%= $eventmemberstatus %> 51 | <% } -%> 52 | <% if $reportholdtime { -%> 53 | reportholdtime=<%= $reportholdtime %> 54 | <% } -%> 55 | <% if $ringinuse { -%> 56 | ringinuse=<%= $ringinuse %> 57 | <% } -%> 58 | <% if $monitor_type { -%> 59 | monitor-type=<%= $monitor_type %> 60 | <% } -%> 61 | <% if ! empty($monitor_format) { -%> 62 | monitor-format=<%= $monitor_format.join('|') %> 63 | <% } -%> 64 | <% if $announce { -%> 65 | announce=<%= $announce %> 66 | <% } -%> 67 | <% if $announce_frequency { -%> 68 | announce-frequency=<%= $announce_frequency %> 69 | <% } -%> 70 | <% if $min_announce_frequency { -%> 71 | min-announce-frequency=<%= $min_announce_frequency %> 72 | <% } -%> 73 | <% if $announce_holdtime { -%> 74 | announce-holdtime=<%= $announce_holdtime %> 75 | <% } -%> 76 | <% if $announce_position { -%> 77 | announce-position=<%= $announce_position %> 78 | <% } -%> 79 | <% if $announce_position_limit { -%> 80 | announce-position-limit=<%= $announce_position_limit %> 81 | <% } -%> 82 | <% if $announce_round_seconds { -%> 83 | announce-round-seconds=<%= $announce_round_seconds %> 84 | <% } -%> 85 | <% if ! empty($periodic_announce) { -%> 86 | periodic-announce=<%= $periodic_announce.join(',') %> 87 | <% } -%> 88 | <% if $periodic_announce_frequency { -%> 89 | periodic-announce-frequency=<%= $periodic_announce_frequency %> 90 | <% } -%> 91 | <% if $random_periodic_announce { -%> 92 | random-periodic-announce=<%= $random_periodic_announce %> 93 | <% } -%> 94 | <% if $relative_periodic_announce { -%> 95 | relative-periodic-announce=<%= $relative_periodic_announce %> 96 | <% } -%> 97 | <% if $queue_youarenext { -%> 98 | queue-youarenext=<%= $queue_youarenext %> 99 | <% } -%> 100 | <% if $queue_thereare { -%> 101 | queue-thereare=<%= $queue_thereare %> 102 | <% } -%> 103 | <% if $queue_callswaiting { -%> 104 | queue-callswaiting=<%= $queue_callswaiting %> 105 | <% } -%> 106 | <% if $queue_holdtime { -%> 107 | queue-holdtime=<%= $queue_holdtime %> 108 | <% } -%> 109 | <% if $queue_minute { -%> 110 | queue-minute=<%= $queue_minute %> 111 | <% } -%> 112 | <% if $queue_minutes { -%> 113 | queue-minutes=<%= $queue_minutes %> 114 | <% } -%> 115 | <% if $queue_seconds { -%> 116 | queue-seconds=<%= $queue_seconds %> 117 | <% } -%> 118 | <% if $queue_thankyou { -%> 119 | queue-thankyou=<%= $queue_thankyou %> 120 | <% } -%> 121 | <% if $queue_reporthold { -%> 122 | queue-reporthold=<%= $queue_reporthold %> 123 | <% } -%> 124 | <% if $wrapuptime { -%> 125 | wrapuptime=<%= $wrapuptime %> 126 | <% } -%> 127 | <% if $timeout { -%> 128 | timeout=<%= $timeout %> 129 | <% } -%> 130 | <% if $timeoutrestart { -%> 131 | timeoutrestart=<%= $timeoutrestart %> 132 | <% } -%> 133 | <% if $timeoutpriority { -%> 134 | timeoutpriority=<%= $timeoutpriority %> 135 | <% } -%> 136 | <% if $retry { -%> 137 | retry=<%= $retry %> 138 | <% } -%> 139 | <% if $autofill { -%> 140 | autofill=<%= $autofill %> 141 | <% } -%> 142 | <% if $autopause { -%> 143 | autopause=<%= $autopause %> 144 | <% } -%> 145 | <% if $setinterfacevar { -%> 146 | setinterfacevar=<%= $setinterfacevar %> 147 | <% } -%> 148 | <% if $setqueuevar { -%> 149 | setqueuevar=<%= $setqueuevar %> 150 | <% } -%> 151 | <% if $setqueueentryvar { -%> 152 | setqueueentryvar=<%= $setqueueentryvar %> 153 | <% } -%> 154 | -------------------------------------------------------------------------------- /templates/snippet/sip.epp: -------------------------------------------------------------------------------- 1 | ; THIS FILE IS MANAGED BY PUPPET 2 | ; all local modifications will be lost 3 | [<%= $peer_name %>]<% if $template_name { %>(<%= $template_name %>)<% } %> 4 | <% if $account_type { -%> 5 | type=<%= $account_type %> 6 | <% } -%> 7 | <% if $username { -%> 8 | username=<%= $username %> 9 | <% } -%> 10 | <% if $defaultuser { -%> 11 | defaultuser=<%= $defaultuser %> 12 | <% } -%> 13 | <% if $secret { -%> 14 | secret=<%= $secret.unwrap %> 15 | <% } -%> 16 | <% if $md5secret { -%> 17 | md5secret=<%= $md5secret %> 18 | <% } -%> 19 | <% if $remotesecret { -%> 20 | secret=<%= $remotesecret.unwrap %> 21 | <% } -%> 22 | <% if $context { -%> 23 | context=<%= $context %> 24 | <% } -%> 25 | <% if $canreinvite { -%> 26 | canreinvite=<%= $canreinvite %> 27 | <% } -%> 28 | <% if $directmedia { -%> 29 | directmedia=<%= $directmedia %> 30 | <% } -%> 31 | <% if $real_directrtpsetup { -%> 32 | directrtpsetup=<%= $real_directrtpsetup %> 33 | <% } -%> 34 | <% $directmediadeny.each |$dmdeny| { -%> 35 | directmediadeny=<%= $dmdeny %> 36 | <% } -%> 37 | <% $directmediapermit.each |$dmpermit| { -%> 38 | directmediapermit=<%= dmpermit %> 39 | <% } -%> 40 | <% if $host { -%> 41 | host=<%= $host %> 42 | <% } -%> 43 | <% if $insecure { -%> 44 | insecure=<%= $insecure %> 45 | <% } -%> 46 | <% if $language { -%> 47 | language=<%= $language %> 48 | <% } -%> 49 | <% if $nat { -%> 50 | nat=<%= $nat %> 51 | <% } -%> 52 | <% if $qualify { -%> 53 | qualify=<%= $qualify %> 54 | <% } -%> 55 | <% if $vmexten { -%> 56 | vmexten=<%= $vmexten %> 57 | <% } -%> 58 | <% if $fromdomain { -%> 59 | fromdomain=<%= $fromdomain %> 60 | <% } -%> 61 | <% if $fromuser { -%> 62 | fromuser=<%= $fromuser %> 63 | <% } -%> 64 | <% if $account_type == 'peer' and $outboundproxy { -%> 65 | outboundproxy=<%= $outboundproxy %> 66 | <% } -%> 67 | <% if $callerid { -%> 68 | callerid=<%= $callerid %> 69 | <% } -%> 70 | <% if $call_limit { -%> 71 | call-limit=<%= $call_limit %> 72 | <% } -%> 73 | <% if $callgroup { -%> 74 | callgroup=<%= $callgroup %> 75 | <% } -%> 76 | <% if $t38pt_udptl { -%> 77 | t38pt_udptl=<%= $t38pt_udptl %> 78 | <% } -%> 79 | <% if $mailbox { -%> 80 | mailbox=<%= $mailbox %> 81 | <% } -%> 82 | <% if $pickupgroup { -%> 83 | pickupgroup=<%= $pickupgroup %> 84 | <% } -%> 85 | <% $disallow.each |$dproto| { -%> 86 | disallow=<%= $dproto %> 87 | <% } -%> 88 | <% $allow.each |$aproto| { -%> 89 | allow=<%= $aproto %> 90 | <% } -%> 91 | <% if $dtmfmode { -%> 92 | dtmfmode=<%= $dtmfmode %> 93 | <% } -%> 94 | <% if ! empty($transports) { -%> 95 | transport=<%= $transports.join(',') %> 96 | <% } -%> 97 | <% if $encryption { -%> 98 | encryption=<%= $encryption %> 99 | <% } -%> 100 | <% if $trustrpid { -%> 101 | trustrpid=<%= $trustrpid %> 102 | <% } -%> 103 | <% if $sendrpid { -%> 104 | sendrpid=<%= $sendrpid %> 105 | <% } -%> 106 | <% 107 | $access.each |$acc| { 108 | $acc.each |$type, $spec| { 109 | -%> 110 | <%= $type %>=<%= $spec %> 111 | <% 112 | } 113 | } 114 | -%> 115 | -------------------------------------------------------------------------------- /templates/snippet/voicemail.epp: -------------------------------------------------------------------------------- 1 | [<%= $context %>] 2 | <%= $voicemail %> => <%= $password.unwrap %>,<% if $user_name { -%><%= $user_name %><% } -%>,<% if $email { -%><%= $email %><% } -%>,<% if $pager_email { -%><%= $pager_email %><% } -%><% if ! empty($options) { -%>,<%= $options.map |$key, $value| { "${key}=${value}" }.join("|") %><% } -%> 3 | 4 | -------------------------------------------------------------------------------- /tests/Puppetfile: -------------------------------------------------------------------------------- 1 | forge 'https://forgeapi.puppetlabs.com' 2 | 3 | mod 'lelutin-asterisk', 4 | git: '/vagrant/' 5 | -------------------------------------------------------------------------------- /tests/init.pp: -------------------------------------------------------------------------------- 1 | # The baseline for module testing used by Puppet Labs is that each manifest 2 | # should have a corresponding test manifest that declares that class or defined 3 | # type. 4 | # 5 | # Tests are then run by using puppet apply --noop (to check for compilation 6 | # errors and view a log of events) or by fully applying the test in a virtual 7 | # environment (to compare the resulting system state to the desired state). 8 | # 9 | # Learn more about module testing here: 10 | # http://docs.puppetlabs.com/guides/tests_smoke.html 11 | # 12 | include asterisk 13 | -------------------------------------------------------------------------------- /tests/one_of_all.pp: -------------------------------------------------------------------------------- 1 | # This test file is meant to be a quick and dirty acceptance test for the main 2 | # class without arguments and the most simple case for all of the defined 3 | # types. Its purpose is to make it easy to see if something got broken somehow. 4 | 5 | class { 'asterisk': 6 | extensions_globals => { 7 | 'TRUNK' => 'patate', 8 | 'CHUNKAWOMBA' => Sensitive.new('megamega'), 9 | } 10 | } 11 | 12 | asterisk::agent { 'smith': 13 | ext => '7000', 14 | password => Sensitive.new('misssteranderson'), 15 | agent_name => 'smith', 16 | } 17 | 18 | asterisk::extensions { 'press_one': 19 | content => 'exten => 500,1,Answer', 20 | } 21 | 22 | asterisk::feature { 'exclusivity': 23 | options => { 24 | phone => '555-555-5555', 25 | } 26 | } 27 | 28 | asterisk::iax { 'meetingroom': 29 | content => "type=user\ncontext=press_one", 30 | } 31 | 32 | asterisk::language { 'fr-armelle': } 33 | 34 | asterisk::manager { 'michael': 35 | secret => Sensitive.new('notagoodmanager'), 36 | } 37 | 38 | asterisk::queue { 'tail': } 39 | 40 | asterisk::sip { 'skippy': } 41 | 42 | asterisk::voicemail { '200': 43 | context => 'press_one', 44 | password => Sensitive.new('whoyougonnacall'), 45 | } 46 | 47 | asterisk::registry::iax { 'providerX': 48 | server => 'foo.local', 49 | user => 'carolina', 50 | password => Sensitive.new('thisisapasswordwhatyoulookingat'), 51 | } 52 | 53 | asterisk::registry::sip { 'myphone': 54 | server => 'sipphone.local', 55 | user => 'line1', 56 | } 57 | 58 | -------------------------------------------------------------------------------- /types/access.pp: -------------------------------------------------------------------------------- 1 | # @summary A deny or permit line for Asterisk configuration 2 | # 3 | # A couple of configuration files let administrators configure accesses. They 4 | # are usually order-dependent so one can interleave permit and deny lines to 5 | # create complex permissions. 6 | type Asterisk::Access = Hash[Enum['permit','deny'], String[1], 1, 1] 7 | -------------------------------------------------------------------------------- /types/extglobalvars.pp: -------------------------------------------------------------------------------- 1 | # @summary A hash of global variables for the dialplan 2 | # 3 | type Asterisk::ExtGlobalVars = Hash[String, Variant[String,Sensitive]] 4 | -------------------------------------------------------------------------------- /types/featuremap.pp: -------------------------------------------------------------------------------- 1 | # @summary Options that can be set for featuremap 2 | # 3 | # Those are the possible values that one could find in the `[featuremap]` 4 | # section of `features.conf`. 5 | # 6 | # @see http://asteriskdocs.org/en/3rd_Edition/asterisk-book-html-chunk/AdditionalConfig_id256654.html#AdditionalConfig_id243783 List of featuremaps and their meangings 7 | # 8 | type Asterisk::Featuremap = Struct[{ 9 | Optional[blindxfer] => String[1], 10 | Optional[disconnect] => String[1], 11 | Optional[automon] => String[1], 12 | Optional[atxfer] => String[1], 13 | Optional[parkcall] => String[1], 14 | Optional[automixmon] => String[1], 15 | }] 16 | -------------------------------------------------------------------------------- /types/featuresgeneral.pp: -------------------------------------------------------------------------------- 1 | # @summary Possible values for the `[general]` section of features.conf 2 | # 3 | # @see http://asteriskdocs.org/en/3rd_Edition/asterisk-book-html-chunk/AdditionalConfig_id256654.html#AdditionalConfig_id244340 List of options and their meaning 4 | # 5 | type Asterisk::Featuresgeneral = Struct[{ 6 | Optional[parkext] => String[1], 7 | Optional[parkpos] => String[1], 8 | Optional[context] => String[1], 9 | Optional[parkinghints] => Enum['yes','no'], 10 | Optional[parkingtime] => Integer, 11 | Optional[comebacktoorigin] => Enum['yes','no'], 12 | Optional[courtesytone] => String[1], 13 | Optional[parkedplay] => Enum['callee','caller','both','no'], 14 | Optional[parkedcalltransfers] => Enum['callee','caller','both','no'], 15 | Optional[parkedcallreparking] => Enum['callee','caller','both','no'], 16 | Optional[parkedcallhangup] => Enum['callee','caller','both','no'], 17 | Optional[parkedcallrecording] => Enum['callee','caller','both','no'], 18 | Optional[parkeddynamic] => Enum['yes','no'], 19 | Optional[adsipark] => Enum['yes','no'], 20 | Optional[findslot] => Enum['first','next'], 21 | Optional[parkedmusicclass] => String[1], 22 | Optional[transferdigittimeout] => Integer, 23 | Optional[xfersound] => String[1], 24 | Optional[xferfailsound] => String[1], 25 | Optional[pickupexten] => String[1], 26 | Optional[pickupsound] => String[1], 27 | Optional[pickupfailsound] => String[1], 28 | Optional[featuredigittimeout] => Integer, 29 | Optional[atxfernoanswertimeout] => Integer, 30 | Optional[atxferdropcall] => Enum['yes','no'], 31 | Optional[atxferloopdelay] => Integer, 32 | Optional[atxfercallbackretries] => Integer, 33 | }] 34 | -------------------------------------------------------------------------------- /types/logfile.pp: -------------------------------------------------------------------------------- 1 | # @summary Options that can be set for a log file 2 | # 3 | # @see https://wiki.asterisk.org/wiki/display/AST/Logging+Configuration 4 | # 5 | type Asterisk::Logfile = Struct[{ 6 | Optional[formatter] => Enum['default','json'], 7 | levels => Array[ 8 | Variant[ 9 | Enum['debug','notice','warning','error','dtmf','fax','security','verbose'], 10 | Pattern[/^verbose\([1-9]\d*\)$/]] 11 | ,1], 12 | }] 13 | -------------------------------------------------------------------------------- /types/managerperms.pp: -------------------------------------------------------------------------------- 1 | # @summary Possible permissions given to AMI users 2 | # 3 | # @see http://asteriskdocs.org/en/3rd_Edition/asterisk-book-html-chunk/AMI-configuration.html#AMI-readwriteopts List of rights and their meaning 4 | # 5 | type Asterisk::ManagerPerms = Enum[ 6 | 'all', 7 | 'system', 8 | 'call', 9 | 'log', 10 | 'verbose', 11 | 'agent', 12 | 'user', 13 | 'config', 14 | 'command', 15 | 'dtmf', 16 | 'reporting', 17 | 'cdr', 18 | 'dialplan', 19 | 'originate', 20 | 'agi', 21 | 'cc', 22 | 'aoc' 23 | ] 24 | --------------------------------------------------------------------------------