├── .aspell.en.prepl
├── .aspell.en.pws
├── .circleci
└── config.yml
├── .gitignore
├── LICENSE
├── Makefile
├── check_build.py
├── doc
├── carrier-numbers
│ ├── docs.md
│ ├── kazoo-carrier.md
│ ├── kazoo-numberdoc.md
│ ├── kazoo-numberlifecycle.md
│ ├── kazoo-provider.md
│ └── routing.md
├── component_overview
│ └── bigcouch.md
├── config
│ ├── account-limits.md
│ ├── account_creation.md
│ ├── adding-ispeech-tts.md
│ ├── basic-sipp.md
│ ├── carrier-modules.md
│ ├── css-custom.md
│ ├── database-health.md
│ ├── dns_concepts.md
│ ├── email-templates.md
│ ├── global-resources.md
│ ├── kazoo-config.md
│ ├── kazoo-mediastream.md
│ ├── limits
│ │ ├── commands.md
│ │ ├── concepts.md
│ │ └── config.md
│ ├── lineman-expect.md
│ ├── lineman-os.md
│ ├── lineman-test.md
│ ├── milliwatt-config.md
│ ├── monitor-maintain.md
│ ├── registrar-design.md
│ ├── ssl
│ │ ├── .org
│ │ │ └── easy_setup.org
│ │ ├── easy_setup.md
│ │ ├── for_api.md
│ │ ├── for_tls.md
│ │ └── for_wss.md
│ ├── sup-command.md
│ └── system_config.md
├── crossbar
│ ├── api-design.md
│ ├── authentication.md
│ ├── haproxy.md
│ └── rest-ssl.md
├── extending
│ └── authz.md
├── install
│ ├── .org
│ │ ├── configure_kazoo.org
│ │ └── install_via_centos7.org
│ ├── configure_kazoo.md
│ ├── downloading.md
│ ├── downloading_packages_securely.md
│ ├── install_manually_centos.md
│ ├── install_manually_debian.md
│ ├── install_overview.md
│ ├── install_via_centos7.md
│ ├── install_via_cluster_manager.md
│ ├── install_via_debian.md
│ ├── install_via_iso.md
│ ├── install_via_rpm.md
│ ├── minimum_requirements.md
│ └── planning_zones.md
├── intro
│ ├── about.md
│ ├── advanced-concepts.md
│ ├── build-own.md
│ ├── build_system.md
│ ├── cluster-design.md
│ ├── component_overview
│ │ └── intro.md
│ ├── contributing.md
│ ├── create-template.md
│ ├── disabling-servers.md
│ ├── distributed-reg.md
│ ├── expand-cluster.md
│ ├── g729-licensing.md
│ ├── get_help.md
│ ├── getting-started.md
│ ├── happy-programmer.md
│ ├── inbound-call-fail.md
│ ├── inbound-call-issue.md
│ ├── kazoo-couch.md
│ ├── kazoo-media.md
│ ├── load-failure.md
│ ├── milliwatt.md
│ ├── number-lifecycle.md
│ ├── read_me_first.md
│ ├── resources.md
│ ├── startup-sequence.md
│ └── storefwd.md
├── kazoo
│ ├── call-rating.md
│ ├── cluster-guide.md
│ ├── dedicated-fs.md
│ ├── ecallmgr-cmd.md
│ ├── enable-cnam.md
│ ├── home-page.md
│ ├── kazoo-debug.md
│ ├── kazoo-servermisc.md
│ ├── kazoo-uimisc.md
│ ├── open-source.md
│ ├── optimize-kazoo-ui.md
│ ├── rating-engine.md
│ ├── service-limits.md
│ ├── service-plans.md
│ ├── sip-flowchart.md
│ └── tdm.md
├── mkdocs
│ ├── index.md
│ └── mkdocs.yml
├── monster
│ ├── login-issues.md
│ └── optimize-monster.md
├── operation
│ ├── cluster-health.md
│ ├── ets-persist.md
│ ├── login-noapps.md
│ ├── monitoring.md
│ └── shared_line_appearance.md
├── provisioner
│ └── README.md
├── security
│ └── iptables.md
├── whapp
│ ├── build.md
│ ├── jonny5.md
│ └── stepswitch.md
└── whitelabeling
│ └── voicemail_to_email.md
├── fix_docs.bash
├── make
└── splchk.mk
├── scripts
├── reconcile_docs_to_index.bash
├── setup_docs.bash
└── validate_mkdocs.py
└── wiki
├── Confluence-space-export-153629.html.zip
├── Dedicated
├── attachments
│ ├── 4194375
│ │ ├── 17694721
│ │ ├── 17694723
│ │ ├── 17694722.png
│ │ └── 17694724.png
│ ├── 4194509
│ │ ├── 43515905.jpg
│ │ ├── 43515906.jpg
│ │ ├── 43515907.jpg
│ │ ├── 43515908.jpg
│ │ ├── 43515909.jpg
│ │ ├── 43515910.jpg
│ │ ├── 43515911.jpg
│ │ ├── 43515912.jpg
│ │ ├── 43515913.png
│ │ └── 43515914.jpg
│ ├── 6488074
│ │ └── 6520834.jpg
│ ├── 6979633
│ │ ├── 7208962
│ │ ├── 7208964
│ │ ├── 7208966
│ │ ├── 7208968
│ │ ├── 7634945
│ │ ├── 30015571
│ │ ├── 66453506
│ │ ├── 66453508
│ │ ├── 66453510
│ │ ├── 151650307
│ │ ├── 151650308.png
│ │ ├── 30015572.png
│ │ ├── 66453507.png
│ │ ├── 66453509.png
│ │ ├── 66453511.png
│ │ ├── 7208963.png
│ │ ├── 7208965.png
│ │ ├── 7208967.png
│ │ ├── 7208969.png
│ │ └── 7634946.png
│ ├── 7504053
│ │ ├── 7634947
│ │ ├── 7634949
│ │ ├── 7634948.png
│ │ └── 7634950.png
│ ├── 7504155
│ │ ├── 7634951.png
│ │ ├── 7634952.png
│ │ ├── 7634953.png
│ │ ├── 7634954.png
│ │ └── 7634955.png
│ ├── 13926531
│ │ ├── 14155781
│ │ ├── 14155783
│ │ ├── 14155785
│ │ ├── 14155782.png
│ │ ├── 14155784.png
│ │ └── 14155786.png
│ ├── 17269210
│ │ ├── 17694734
│ │ └── 17694735.png
│ └── 22020107
│ │ └── 22216705.png
├── images
│ └── icons
│ │ ├── bullet_blue.gif
│ │ ├── contenttypes
│ │ └── home_page_16.png
│ │ └── grey_arrow_down.png
├── service-plans
│ └── intro.md
└── styles
│ └── site.css
└── parse_wiki.py
/.aspell.en.prepl:
--------------------------------------------------------------------------------
1 | personal_repl-1.1 en 0 utf-8
2 | whapps kapps
3 | justs just
4 | unwieldly unwieldy
5 | likelyhood likelihood
6 | wnm knm
7 | thusly thus
8 |
--------------------------------------------------------------------------------
/.aspell.en.pws:
--------------------------------------------------------------------------------
1 | personal_ws-1.1 en 73 utf-8
2 | SHA
3 | IPs
4 | hostnames
5 | CNAM
6 | AMQP
7 | dialplan
8 | ATAs
9 | PSTN
10 | JSON
11 | softswitch
12 | URI
13 | UI
14 | PSAP
15 | rebar
16 | genrsa
17 | config
18 | DHE
19 | HAProxy
20 | sharding
21 | FreeBSD
22 | kapps
23 | ECM
24 | DIDs
25 | ACLs
26 | MongoDB
27 | RSA
28 | Erlang
29 | IVR
30 | transcode
31 | knm
32 | INVITEs
33 | AES
34 | balancers
35 | CDRs
36 | Kamailio
37 | balancer
38 | SMS
39 | schemas
40 | APIs
41 | telcos
42 | ZeroMQ
43 | RTP
44 | rsync
45 | FreeSWITCH
46 | CouchDB
47 | openssl
48 | CSR
49 | DNS
50 | CSS
51 | BigCouch
52 | TLS
53 | RabbitMQ
54 | telco
55 | PCMU
56 | SSL
57 | cURL
58 | datastore
59 | req
60 | CentOS
61 | transcoding
62 | IVRs
63 | PSAPs
64 | Codecs
65 | plaintext
66 | repo
67 | FQDN
68 | WAV
69 | latencies
70 | Schreiber
71 | CAkey
72 | codec
73 | natively
74 | ATA
75 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | machine:
2 | python:
3 | version: 2.7.13
4 | post:
5 | - pyenv global 2.7.13
6 |
7 | dependencies:
8 | pre:
9 | - pip -q install --upgrade pip
10 | - pip -q install PyYAML mkdocs pyembed-markdown
11 |
12 | test:
13 | pre:
14 | - make docs
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /doc/index.md
2 | /doc/mkdocs/mkdocs.local.yml
3 | /site
4 | /doc/mkdocs/docs/
5 | /doc/mkdocs/site/
6 | /doc/mkdocs/theme/
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 2600Hz Kazoo and Monster UI
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | ROOT = $(shell readlink -f .)
2 | DOCS_ROOT=$(ROOT)/doc/mkdocs
3 |
4 | include make/splchk.mk
5 |
6 | docs: docs-report docs-setup docs-build
7 |
8 | docs-report:
9 | @$(ROOT)/scripts/reconcile_docs_to_index.bash
10 |
11 | docs-setup:
12 | @$(ROOT)/scripts/validate_mkdocs.py
13 | @$(ROOT)/scripts/setup_docs.bash
14 | @cp $(DOCS_ROOT)/mkdocs.yml $(DOCS_ROOT)/mkdocs.local.yml
15 | @mkdir -p $(DOCS_ROOT)/theme
16 | @if [ -f $(DOCS_ROOT)/theme/global.yml ]; then cat $(DOCS_ROOT)/theme/global.yml >> $(DOCS_ROOT)/mkdocs.local.yml; fi
17 |
18 | docs-build:
19 | @echo "\ntheme: null\ntheme_dir: '$(DOCS_ROOT)/theme'\ndocs_dir: '$(DOCS_ROOT)/docs'\n" >> $(DOCS_ROOT)/mkdocs.local.yml
20 | @cp $(DOCS_ROOT)/index.md $(ROOT)/doc/index.md
21 | @mkdocs build -f $(DOCS_ROOT)/mkdocs.local.yml --clean -q --site-dir $(DOCS_ROOT)/site
22 |
23 | docs-serve: docs-build
24 | @mkdocs serve --dev-addr=0.0.0.0:9876 -f $(DOCS_ROOT)/mkdocs.local.yml
25 |
26 | docs-clean:
27 | @rm -rf $(DOCS_ROOT)/site $(DOCS_ROOT)/docs $(DOCS_ROOT)/mkdocs.local.yml
28 |
--------------------------------------------------------------------------------
/check_build.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import yaml, os.path
4 |
5 | def parse_page(page):
6 | "parse a page for existence"
7 | if isinstance(page, dict):
8 | for header, pages in page.items():
9 | if pages is None:
10 | print "section ", header, " is incomplete"
11 | else:
12 | parse_page(pages)
13 | elif isinstance(page, list):
14 | for p in page:
15 | parse_page(p)
16 | elif isinstance(page, str):
17 | if "index.md" != page and (not os.path.isfile(page)):
18 | print "page ", page, " is not valid"
19 |
20 | stream = open("doc/mkdocs/mkdocs.yml", 'r')
21 | mkdocs = yaml.load_all(stream)
22 |
23 | for doc in mkdocs:
24 | for k,v in doc.items():
25 | if "pages" == k:
26 | parse_page(v)
27 |
--------------------------------------------------------------------------------
/doc/carrier-numbers/docs.md:
--------------------------------------------------------------------------------
1 | ## Kazoo Number Manager
2 |
--------------------------------------------------------------------------------
/doc/carrier-numbers/kazoo-carrier.md:
--------------------------------------------------------------------------------
1 | ## Building a Carrier Module
2 |
3 |
4 |
5 | ## Hooking a Carrier's API into Kazoo
6 |
7 | More and more carriers are starting to offer API access to their number search, number provisioning, and other services. Kazoo has a generic method it uses to access these features, allowing the enterprising developer to add a module to Kazoo that does the integration between the carrier and Kazoo. This page will serve as a developer's guide to creating that module.
8 |
9 |
10 | ## Overview
11 |
12 | Carrier modules exist as part of the core's whistle_number_manager application. You can view existing modules in src/carriers/ to help guide your development efforts. A carrier module must export the following functions (this is the **Kazoo** interface):
13 | ```
14 | find_numbers/3
15 | acquire_number/1
16 | disconnect_number/1
17 | find_number/3
18 | ```
19 | This is what **Crossbar** and other modules within **Kazoo** would use to search for numbers from a given carrier. The function accepts three arguments and should return a JSON object OK 2-tuple or an error 2-tuple. The first argument is the prefix or number to search for; this will depend on what types of searches the carrier's API supports. It could be the NPA or NPA-NXX in the US, or some other search criteria. The second argument is the quantity of numbers requested by **Kazoo**. The third argument is a proplist, usable for passing carrier-specific options to the underlying module. The JSON object returned should have, as top-level keys, the DIDs found, and the value should be a JSON object containing any additional information (like rate center, features on the number, etc). A sample return could be:
20 | ```
21 | {"+12223334444":{"sms":"enabled"}
22 | ,"+12223334445":{"sms":"disabled", "ratecenter":"OR"}
23 | }
24 |
25 | acquire_number/1
26 | ```
27 | This function is responsible for actually provisioning a number from the carrier and having the carrier route the DID to the **Kazoo** installation. It takes as input the #number{} record and expects the modified record back. Typically all that is modified is the `module_data` portion, which is generally appended with any order information the carrier may return. If an error occurs when provisioning the number, use the `knm_number:error_*` functions to throw an appropriate exception. Some carriers will allow you to dynamically add the IP(s) to use when routing the DID to the **Kazoo** cluster. These are typically stored in the `system_config` database in a document for the carrier settings (something like `number_manager.carrier_name`).
28 |
29 | Each `acquire_number` function should also have a dry run capability:
30 |
31 | `acquire_number(#number{dry_run='true'}=Number) -> Number;`
32 |
33 | This allow to bypass the work and not actually buy the number but the rest of the work in **Kazoo** is done. This will return you an updated service plan with the charges that would happen if you bought the number (this work will appear in phone_numbers V2 APIs).
34 |
35 | `disconnect_number/1`
36 |
37 | This function is responsible to releasing the DID from the carrier. Similar to `acquire_number/1`, this function will only return the `#number{}` record on success; otherwise use the `knm_number` error functions to throw exceptions when this function should fail.
38 |
--------------------------------------------------------------------------------
/doc/carrier-numbers/kazoo-numberdoc.md:
--------------------------------------------------------------------------------
1 | ## Number Document
2 |
3 |
4 |
5 | ## Number Document
6 |
7 | The number document is the only document used to route inbound calls that originate from a source not associated with an account such as a carrier. Any number that matches the `reconcile_regex`, in the configuration, will generate a number document in the associated database when saved. If the database is not present it will be created the when required. The UI uses a numbers document that is stored in the account database to display the numbers which is kept in synchronization with changes by the number manager. If you make manual changes you will need to also update this document.
8 |
9 |
10 | ## Database
11 |
12 | Number documents are stored in a database based on the prefix of the number after E.164 converters have been applied. All number databases start with "numbers/" followed by the first five digits of the number. For example, 4158867900 would be stored in a database called "numbers/+1415" (URL encoded as "numbers%2F%2B415").
13 |
14 |
15 | ## Base Parameters
16 |
17 | `PROVIDER_PROPERTIES` - These are provider specific properties that are added to enable some feature (via a provider module). See below for sub-parameters:
18 |
19 | `pvt_module_name` - This property sets carrier module that is responsible for the number. For example if this is set to `knm_some_carrier` then the API module for "Some Carrier" would be used to provision the number or disconnect it.
20 |
21 | `pvt_module_data` - This property is opaque metadata needed by the carrier module to maintain the number. This property should never be manipulated or used by anything other than the carrier module.
22 |
23 | `pvt_number_state` - This property tracks the state in accordance with the Number Lifecycle.
24 |
25 | `pvt_authorizing_account` - This property is the account id that was used to create the number, it is set only during creation and never changes.
26 |
27 | `pvt_assigned_to` - This is the most important property of a number. It is the account id that the number should route to and will only be set on a number that is `in_service` or reserved.
28 |
29 | `pvt_previously_assigned_to` - When an account deletes a number maintained by a carrier module other than knm_local it will transition to the `released_state` (as set in the configuration). When this happens the `pvt_assigned_to` will be cleared and this property will be populated with the account id that it was assigned to.
30 |
31 | `pvt_features` - This property is used to track what features (as supported by provider modules) are active on the number. When a provider is triggered by adding the appropriate properties it will automatically add or remove the associated feature to this list. The primary use of this is for the billing/services module. This parameter is maintained by the number manager and should not be changed directly.
32 |
33 | `pvt_reserve_history` - When an account reserves a number it is added to this ordered list of account ids. As accounts delete the number this list will be used to reserve the number in the next account that previously reserved it. For example, a parent account might reserve a number for use on a sub-account, which adds itself to the reserve history. The subaccount may then acquire the number and use it for a period of time, eventually deleting it. When this happens the number will revert to being reserved on the parent account, instead of moving to a released state. It is only when a number is removed from an account with no reserve history that it actually moves to the released state.
34 |
35 | `pvt_ported_in` - This property is used to track numbers that where created as a port in request.
36 |
37 | `pvt_created` - This is the timestamp that the number was created on, in Gregorian seconds.
38 |
39 | `pvt_modified` - This is the timestamp that the number was lasted modified on, in Gregorian seconds.
40 |
41 | `pvt_db_name` - This is the URL encoded database name that the number document is stored in.
42 |
43 |
44 | ## Sub-Parameters
45 | ```
46 | cnam
47 | port
48 | dash_e911
49 |
50 | ```
51 |
--------------------------------------------------------------------------------
/doc/carrier-numbers/kazoo-numberlifecycle.md:
--------------------------------------------------------------------------------
1 | ## Number Lifecycle
2 |
3 |
4 |
5 | ## Number Lifecycle
6 |
7 | This document describes the lifecycle of direct inward dialing (DID) numbers.
8 |
9 |
10 | ## Number States
11 |
12 |
13 | ## Discovery
14 |
15 | This is an internal number state used to temporarily hold information regarding numbers users can acquire from the system owner carriers.
16 |
17 | Populated (usually) by API requests to the carriers.
18 |
19 | Does not participate in number hunts.
20 |
21 | No accounts have authority to transition to/from this state.
22 |
23 | There are no public fields for "discovery" numbers.
24 |
25 | Any account can transition an "available" number to "reserved".
26 |
27 |
28 | ## Port In
29 |
30 | This is a temporary state for a newly added number by an account via the porting API.
31 |
32 | Automatically transitions to `in_service` the first time hunted by the system (first call to it).
33 |
34 | Does not participate in the `off-net` number hunt, meaning it is only used to route inbound and will not keep calls on-net.
35 |
36 | No accounts have authority to transition to/from this state.
37 |
38 | Any account can create a `port_in number` if it does not exist in the system.
39 |
40 | The public fields of a `port_in` number can be managed by the assigned account or an ancestor of the assigned account.
41 |
42 | Only numbers in the `port_in` state allow the porting documents to be managed.
43 |
44 | These numbers can only exist in states `in_service`, `port_out`, and `disconnected`. None of these transitions can be preformed by accounts.
45 |
46 |
47 | ## Available
48 |
49 | This is a number that has been routed to the cluster but has no account assignment.
50 |
51 | Any account can transition these numbers to `reserved` or `in_service` if they wish to obtain control of it.
52 |
53 | Does not participate in number hunts.
54 |
55 | Any account can transition an `available` number to `reserved`.
56 |
57 | Any account can transition an `available` number to `in_service` if it is not of type `knm_local`.
58 |
59 | There are no public fields for `available` numbers, but they can be created during a transition.
60 |
61 |
62 | ## Reserved
63 |
64 | This is a number that an account has acquired for themselves or their children. Some accounts can create `reserved` numbers.
65 |
66 | Does not participate in number hunts.
67 |
68 | Numbers coming from the `discovery` state will be acquired via the carrier modules.
69 |
70 |
71 | An account can transition a `reserved` number to `in_service` if one of the following criteria is met:
72 |
73 | The requesting account is the same as the assigned account.
74 |
75 | The requesting account is an ancestor of the assigned account.
76 |
77 | The requesting account is an descendant of the assigned account.
78 |
79 | The new account assignment is the same or a descendant of the current assignment.
80 |
81 |
82 | An account can reserve a `reserved` number if one of the following criteria is met:
83 |
84 | The requesting account is an ancestor of the assigned account.
85 |
86 | The requesting account is an descendant of the assigned account.
87 |
88 | The new account assignment is a descendant of the current assignment.
89 |
90 | When a number is reserved the new assignment is added to the history of assignments.
91 |
92 | A flagged account can create a `reserved` number of type `knm_local`. These numbers can only be acquired and managed by the creating
93 | account or a descendant.
94 |
95 | E911 assignments will be maintained, if present.
96 |
97 | The public fields of a `reserved` number can be managed by the assigned account or an ancestor of the assigned account.
98 |
99 |
100 | ## In Service
101 |
102 | This is a number that belongs to an account.
103 |
104 | Participates in number hunts.
105 |
106 | An `in_service` number can be transitioned to "reserved" if the requesting account is, or an ancestor of, the assigned account for the number.
107 |
108 | E911 assignments will be maintained, if present.
109 |
110 | The public fields of an `in_service` number can be managed by the assigned account or an ancestor of the assigned account.
111 |
112 |
113 | ## Released
114 |
115 | This is an aging state that numbers added to the system via discovery remain for a period of time till moving back to available to start the cycle again.
116 |
117 | Does not participate in number hunts.
118 |
119 | *If a `reserved` number is released:*
120 |
121 | With an assignment history it remains `reserved` but is re-assigned to the previously assigned account.
122 |
123 | Without an assignment history and is of type `knm_local` it transitions to `disconnected`.
124 |
125 | Any other type completes the transition to "released".
126 |
127 | *If an "in_service" number is released:*
128 |
129 | With an assignment history it becomes `reserved` and is re-assigned to the previously assigned account.
130 |
131 | Without an assignment history and is of type `knm_local` it transitions to `disconnected`.
132 |
133 | Any other type completes the transition to `released`.
134 |
135 | The public fields of an `released` number are removed.
136 |
137 | Released numbers can be transitioned to `available` by the system or system admin accounts only.
138 |
139 | E911 is disconnected, if present.
140 |
141 |
142 | ## Port Out
143 |
144 | This is an administrative step to releasing numbers. It operates like "Port In" except that inbound requests do not move it to "In Service".
145 |
146 |
147 | ## Disconnected
148 |
149 | This is an internal number state, and marks the number for a permanent move from the active datastore to the archive.
150 |
--------------------------------------------------------------------------------
/doc/carrier-numbers/kazoo-provider.md:
--------------------------------------------------------------------------------
1 | # Kazoo Provider Module
2 |
3 |
4 |
5 | ## Hooking a Provider's API into Kazoo
6 |
7 | Service providers offer various add-ons to telephony; things like CNAM, E911, and other services can be added to numbers in **Kazoo**. Creating a provider module links **Kazoo** up with the provider's APIs.
8 |
9 |
10 | ## Overview
11 |
12 | Provider modules exist as part of the core's `whistle_number_manager` application. You can view existing modules in src/providers/ to help guide your development efforts. The exported interface varies based on the type of service being provided.
13 |
14 | Services include:
15 | ```
16 | E911
17 | CNAM
18 | Porting
19 | E911
20 | # An E911 provider module will export the following interface:
21 | save/1
22 | delete/1
23 | ```
24 | Each function takes the `#number{}` record and must return a `#number{}` record back to the caller on success. If a failure occurs, an exception is thrown using the `knm_number` error functions.
25 |
--------------------------------------------------------------------------------
/doc/carrier-numbers/routing.md:
--------------------------------------------------------------------------------
1 | ## Numbers Document
2 |
3 |
4 |
5 | The numbers document is only used by the APIs to list numbers and has no impact on routing. It exists to reduce the overhead of the `phone_number` API so every number database does not need to be scanned to determine which numbers are active on an account.
6 | The number document is the only document used for routing, however if you are making changes to this document you should ensure they reflect the number document or the user may be confused by conflicting information in the UI.
7 |
8 |
9 | ## Database
10 |
11 | Numbers document are stored in account databases with the id "phone_numbers".
12 |
13 |
14 | ## Base Parameters
15 |
16 | `NUMBER_PROPERTIES` - For each number associated with an account there will be a number property.
17 |
18 | See below for sub-parameters:
19 |
20 | `pvt_type` - This is the type of document and will always have the value of `phone_numbers` example: `pvt_type : phone_numbers`
21 |
22 | `pvt_vsn` - This is the version of the document and indicates which format you will find the data in. Currently these documents are at the first version: `pvt_vsn : "1"`
23 |
24 | `pvt_created` - This is the timestamp that the number was created on, in Gregorian seconds: `pvt_created : 63494331491`
25 |
26 | `pvt_modified` - This is the timestamp that the number was lasted modified on, in Gregorian seconds: `pvt_modified : 63494331491`
27 |
28 | `pvt_account_db` - This is the URL encoded database of the account: `pvt_account_db : account%2F43%2F57%2F9fc0a3aa11e29e960800200c9a66`
29 |
30 | `pvt_account_id` - This is the id of the account: `pvt_account_db : 43579fc0a3aa11e29e960800200c9a66`
31 | ```
32 | {
33 | "_id": "phone_numbers",
34 | "pvt_account_db": "account%2F43%2F57%2F9fc0a3aa11e29e960800200c9a66",
35 | "pvt_account_id": "43579fc0a3aa11e29e960800200c9a66",
36 | "pvt_vsn": "1",
37 | "pvt_type": "phone_numbers",
38 | "pvt_modified": 63529420348,
39 | "pvt_created": 63520338360,
40 | "+14158867900": {
41 | "state": "in_service",
42 | "features": [
43 | "dash_e911",
44 | "outbound_cnam",
45 | "inbound_cnam"
46 | ],
47 | "on_subaccount": false,
48 | "assigned_to": "43579fc0a3aa11e29e960800200c9a66"
49 | },
50 | "+14158867998": {
51 | "state": "in_service",
52 | "features": [
53 | ],
54 | "on_subaccount": false,
55 | "assigned_to": "43579fc0a3aa11e29e960800200c9a66"
56 | }
57 | }
58 | ```
59 |
60 | ## Sub-Parameters
61 |
62 | `state` - This is the current number state in accordance with the Number Lifecycle.
63 |
64 | `features` - This property is used to display what features (as supported by provider modules) are active on the number. Changing this directly will have no effect on the actual feature.
65 |
66 | `on_subaccount` - This property is used to determine if a number is used by a sub account. For example, if a parent reserves a number then assigns it to a sub account this value will be true.
67 |
68 | `assigned_to` - This property is used to determine which sub account a number might be assigned to. For example, if a parent reserves a number then assigns it to a sub account this value will be the account id of the sub account.
69 |
70 | ```
71 | "+14158867900": {
72 | "state": "in_service",
73 | "features": [
74 | "dash_e911",
75 | "outbound_cnam",
76 | "inbound_cnam"
77 | ],
78 | "on_subaccount": false,
79 | "assigned_to": "43579fc0a3aa11e29e960800200c9a66"
80 | }
81 |
82 | ```
83 |
--------------------------------------------------------------------------------
/doc/component_overview/bigcouch.md:
--------------------------------------------------------------------------------
1 | ## Getting to Know BigCouch
2 |
3 |
4 |
5 | ## Manually Editing Database Documents
6 |
7 | These are the steps required to complete a self install using any of the currently available methods ( Chef-Solo, Packages, or Source Installation). You will access most of these database documents by using the Futon web interface for **Bigcouch**. You can reach it by going to http://ip.address:15984/_utils . Insert the IP Address of your server in the url. Currently we need to manually create the master account on a new deployment. Please replace the (ACCOUNTNAME SIP.REALM.COM USERNAME PASSWORD) placeholders with values that fit your environment.
8 |
9 | `/opt/kazoo/utils/sup/sup crossbar_maintenance create_account ACCOUNTNAME SIP.REALM.COM USERNAME PASSWORD`
10 |
11 | Open your browser and go to **BigCouch** Futon web interface. In the `system_config` database, verify that the `autoload_modules` list in the crossbar document is correct:
12 |
13 | http://ip.address:15984/_utils/document.html?system_config/crossbar
14 | ```
15 | "autoload_modules": [
16 | "cb_user_auth",
17 | "cb_simple_authz",
18 | "cb_vmboxes",
19 | "cb_schemas",
20 | "cb_connectivity",
21 | "cb_temporal_rules",
22 | "cb_webhooks",
23 | "cb_global_provisioner_templates",
24 | "cb_shared_auth",
25 | "cb_users",
26 | "cb_global_resources",
27 | "cb_phone_numbers",
28 | "cb_templates",
29 | "cb_signup",
30 | "cb_accounts",
31 | "cb_groups",
32 | "cb_limits",
33 | "cb_local_provisioner_templates",
34 | "cb_callflows",
35 | "cb_local_resources",
36 | "cb_faxes",
37 | "cb_configs",
38 | "cb_api_auth",
39 | "cb_braintree",
40 | "cb_whitelabel",
41 | "cb_onboard",
42 | "cb_conferences",
43 | "cb_directories",
44 | "cb_registrations",
45 | "cb_token_auth",
46 | "cb_clicktocall",
47 | "cb_media",
48 | "cb_menus",
49 | "cb_cdrs",
50 | "cb_servers",
51 | "cb_devices",
52 | "cb_queues",
53 | "cb_rates"
54 | ]
55 | ```
56 |
57 | Add the FreeSWITCH nodes to the `ecallmgr` document in the `system_config` database. This will instruct `ecallmgr` on which servers to connect to on startup and also what commands to run. In this example, `ecallmgr` will connect to `server1.domain.com` and `server2.domain.com`, run the command `load mod_sofia` and reload the ACLs using the "acls" field. Note that your proxy servers (OpenSIPs or Kamailio) should be in the "authoritative" list while your DID providers should be in the "trusted" list.
58 |
59 | http://ip.address:15984/_utils/document.html?system_config/ecallmgr
60 | ```
61 | {
62 | "_id": "ecallmgr",
63 | "default": {
64 | "fs_nodes": [
65 | "freeswitch@server1.domain.com",
66 | "freeswitch@server2.domain.com"
67 | ],
68 | "syslog_log_level": "info",
69 | "fs_cmds": [
70 | {
71 | "load": "mod_sofia",
72 | "reloadacl": ""
73 | }
74 | ],
75 | "acls": {
76 | "Your Proxy server": {
77 | "type": "allow",
78 | "network-list-name": "authoritative",
79 | "cidr": "xxx.xxx.xxx.xxx/32"
80 | },
81 | "Your DID provider": {
82 | "type": "allow",
83 | "network-list-name": "trusted",
84 | "cidr": "xx.xx.xx.x/24"
85 | }
86 | }
87 | }
88 | }
89 | ```
90 | After performing any edits the database documents we will need to flush the cache and restart crossbar.
91 | ```
92 | /opt/kazoo/utils/sup/sup whapps_config flush
93 | /opt/kazoo/utils/sup/sup -n ecallmgr ecallmgr_config flush
94 | /opt/kazoo/utils/sup/sup whapps_controller restart_app crossbar
95 | ```
96 | You can now point your browser to http://ip.address to start using the **Kazoo** web interface. Use the credentials from Step 1 to log in, then hover on the white arrow next to your user and account info on the top right of the page and click on "App Store" to turn on the apps you want to use. Have fun and thanks for using **Kazoo**!
97 |
--------------------------------------------------------------------------------
/doc/config/account-limits.md:
--------------------------------------------------------------------------------
1 | ## ACCOUNT LIMITS
2 |
3 |
4 |
5 | `twoway_trunks` : 0 //two way flat rate trunks, can only be used if `system_config.jonny5. flat_rate_whitelist` regex matches AND `system_config.jonny5.flat_rate_blacklist` does not. This can also be specified as a `pvt_twoway_trunks`, the lower will be used.
6 |
7 | `inbound_trunks` : 0 //exactly the same as two-way trunks but only used for inbound calls. If there are more inbound calls then trunks two-way trunks will be checked next.
8 |
9 | `resource_consuming_calls` : -1 // hard limit on the number of calls that can consume one or more resources (IE: inbound to outbound forwarded number is one resource consuming call), can also be specified as `pvt_resource_consuming_calls`, the smallest of the two is used
10 |
11 | `calls` : -1 // total number of calls (resource consuming OR NOT) that an account can have, can also be specified as `pvt_calls`, the smallest of the two is used
12 |
13 | `allow_prepay` : true, // allows the customer to disable `per_minute` authorizations relying solely on trunks and/or allotments, this will be overridden by `pvt_allow` prepay
14 |
15 | `pvt_type` : limits
16 |
17 | `pvt_vsn` :
18 |
19 | `pvt_account_id` : d75312345678901234567890
20 |
21 |
22 | `pvt_account_db` : account%2Fd7%2F53%12345678901234567890
23 |
24 | `did_us` : // then classification of a number as per `system_config.number_manager.classifiers`
25 |
26 | `amount` : 120 // the allotment in seconds
27 |
28 | `pvt_created` : 63518278682
29 |
30 | `pvt_modified` : 63518278682
31 |
32 | `pvt_soft_limit_outbound` : false // allows otherwise unauthorized outbound calls to continue
33 |
34 | `pvt_soft_limit_inbound` : true //allows otherwise unauthorized inbound calls to conitnue
35 |
36 | `pvt_allow_prepay` : true
37 |
38 | `pvt_allow_postpay` : true // whether or not to allow the account to go negative
39 |
40 | `pvt_max_postpay_amount` : 100 // the maximum negative amount that is acceptable
41 |
42 | `pvt_allotments`:
43 |
44 | `cycle` : hourly // the allotment reset period: yearly, monthly, weekly, daily, hourly, minutely
45 |
46 | `pvt_discounts`:
47 |
48 | `did_us` : // then classification of a number as per `system_config.number_manager.classifiers`
49 |
50 | `percentage` : 10 // a percentage discount off the rate of EVERY per_minute call
51 |
52 | `pvt_enabeld` : true // should limits be enforced for this account, IF FALSE THE ACCOUNT IS UNRESTRICTED
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/doc/config/adding-ispeech-tts.md:
--------------------------------------------------------------------------------
1 | ## Adding iSpeech TTS to Kazoo
2 |
3 |
4 |
5 | ## iSpeech
6 |
7 | Adding **iSpeech** TTS to **Kazoo** provides a nice TTS engine for turning your dynamic text into a sound file for playing to your callers. Once **Kazoo** is configured properly, **iSpeech** will be used to generate the TTS wav files instead of the `default mod_flite` **FreeSWITCH** module. Generally speaking, the **iSpeech** versions are of a higher quality. As **iSpeech** is a third-party service, you will need to setup and maintain your **iSpeech** account/credits outside of **Kazoo** itself.
8 |
9 |
10 | ## Configure Kazoo to use iSpeech
11 |
12 | 1. Access your **BigCouch**/**CouchDB Futon GUI** (usually located at http://your.host.com:5984/_utils)
13 |
14 | 2. Open up the `system_config` database
15 |
16 | 3. Edit the speech document:
17 | ```
18 | {
19 | "_id" : "speech",
20 | "default": {
21 | "tts_url": "http://api.ispeech.org/api/json",
22 | "tts_api_key": "YOUR_ISPEECH_KEY",
23 | "tts_frequency": "16000",
24 | "tts_bitrate": "16",
25 | "tts_speed": 0,
26 | "tts_start_padding": 1,
27 | "tts_end_padding": 0,
28 | "tts_provider": "ispeech",
29 | "tts_voice": "female",
30 | "tts_language": "en-US",
31 | "tts_default_voice": "female/en-US",
32 | "tts_url_ispeech": "http://api.ispeech.org/api/json"
33 | }
34 | }
35 | ```
36 |
37 | These configs should take effect the next time something (such as directory or **Pivot's** Say) utilizes the TTS commands in **Kazoo**. **Kazoo** will proxy/cache the generated .wav file for a time, and normal **FreeSWITCH** media caching will also take place, so an oft-used TTS string should not require accessing **iSpeech** (resulting in audio delays).
38 |
--------------------------------------------------------------------------------
/doc/config/basic-sipp.md:
--------------------------------------------------------------------------------
1 | ## Basic SIPp Overview
2 |
3 |
4 |
5 | From http://sipp.sourceforge.net/: **SIPp** is a free Open Source test tool / traffic generator for the SIP protocol. It includes a few basic **SipStone** user agent scenarios (UAC and UAS) and establishes and releases multiple calls with the `INVITE` and `BYE` methods. It can also reads custom XML scenario files describing from very simple to complex call flows. It features the dynamic display of statistics about running tests (call rate, round trip delay, and message statistics), periodic CSV statistics dumps, TCP and UDP over multiple sockets or multiplexed with retransmission management and dynamically adjustable call rates. The **2600hz** team has created a repo with some very simple **SIPp** configurations for use as examples.
6 |
7 |
8 | ## Quick Setup
9 |
10 | Install **SIPp** using your package manager: `yum install -y sipp`
11 |
12 | Clone the **2600hz SIPp** example repo onto a server, such as a **Kazoo** app server: `$ git clone git://github.com/2600hz/sipp.git`
13 |
14 | Create a **Kazoo** account with the Realm : sipp.2600hz.com
15 |
16 | On the website hover over 'Voip Services' then click 'Accounts', click 'New Account' and name the account anything you wish.
17 |
18 | Enter into the Realm **sipp.2600hz.com** and save.
19 |
20 | Click 'Use Account'
21 |
22 | Create a **Kazoo** device:
23 | ```
24 | username: user_101
25 | password: pwd_101
26 | ```
27 |
28 | Hover over 'Voip Services' then click 'Devices',
29 |
30 | Click 'Add Device' then click 'SIP Device' and give the device any name you wish.
31 |
32 | Click 'Advanced Settings'then go to the SIP Setting and change:
33 |
34 | ```
35 | username: user_101
36 | password: pwd_101
37 | ```
38 |
39 | Click 'Save'
40 |
41 | Create a **Kazoo** device:
42 | ```
43 | username: user_102
44 | password: pwd_102
45 | ```
46 |
47 | Click 'Add Device'
48 |
49 | Click 'SIP Device' and give the device any name you wish.
50 |
51 | Click 'Advanced Settings' then go to the 'SIP Setting'
52 |
53 | From there change:
54 |
55 | ```
56 | username: user_102
57 | password: pwd_102
58 | ```
59 |
60 | Click 'Save'.
61 |
62 | Create a **Kazoo** device with:
63 |
64 | ```
65 | username: user_103
66 | password: pwd_103
67 | ```
68 |
69 | Click 'Add Device'
70 |
71 | Click 'SIP Device' and give the device any name you wish.
72 |
73 | Click 'Advanced Settings' then go to 'SIP Setting'
74 |
75 | Change:
76 |
77 | ```
78 | username: user_103
79 | password: pwd_103
80 | ```
81 |
82 | Click 'Save'.
83 |
84 | Enable the 'Check Voicemail' feature code on the account. Hover over 'Voip Services' then click 'Feature Codes'and expand the 'Miscellaneous'section.
85 |
86 | Click the 'Enabled'box by the 'Check Voicemail' feature code and click 'Save'. The **SIPp** test account does not need phone numbers, callflows, or voicemials unless you plan to test them.
87 |
88 |
89 | ## Calls to Voicemail with Authentication
90 |
91 | ```
92 | call_with_auth.sh
93 | cd dirname $0
94 | sipp -inf users.csv -sf uac_auth.xml -r 1 -d 1000 -s *97 -i 192.168.5.42 192.168.5.151`
95 | -r 1
96 | ```
97 |
98 | This is the number of calls to start every second, it can be changed while the test it running
99 |
100 | `-d 1000`
101 |
102 | This is how long each call should remain up, in milliseconds
103 |
104 | `-s *97`
105 |
106 | This is is the number to call, in this case the default check voicemail feature code.
107 |
108 | `-i 192.168.5.42`
109 |
110 | This is the IP address to bind to, you will need to set this to the IP of the server running **SIPp**.
111 |
112 | `192.168.5.151 `
113 |
114 | This is the IP address of the **FreeSWITCH** server to test. Change the two IP address to be the address of the test server and the address of a **FreeSWITCH** server (in that order). When you run this test it will round robin between the SIP credentials in `users.csv` running the test `uac_auth.xml`.
115 |
116 | To start the test type:
117 |
118 | `$ ./call_with_auth.sh`
119 |
120 |
121 | ## Register
122 |
123 | Edit:
124 | ```
125 | register.sh
126 | cd dirname $0
127 | sipp -inf users.csv -sf register.xml -d 1000 -s 5000 -i 192.168.5.42 192.168.5.151`
128 | -d 1000
129 | ```
130 | This is ignored by this test
131 |
132 | `-s 5000 `
133 |
134 | This is ignored by this test
135 |
136 | `-i 192.168.5.42`
137 |
138 | This is the IP address to bind to, you will need to set this to the IP of the server running **SIPp**
139 |
140 | `192.168.5.151 `
141 |
142 | This is the IP address of the **FreeSWITCH** server to test.
143 |
144 | Change the two IP address to be the address of the test server and the address of a **FreeSWITCH** server (in that order). When you run this test it will round robin between the SIP credentials in `users.csv` running the test `register.xml.`
145 |
146 | To start the test type:
147 |
148 | `$ ./register.sh`
149 |
150 |
151 | ## Leave Voicemails
152 |
153 | Create a 'Voicemail Box' under the **SIPp** test account and create a callflow that goes to that 'Voicemail Box' with the number 5000:
154 |
155 | #Edit
156 | ```
157 | leave_vm.sh
158 | cd dirname $0
159 | sipp -inf users.csv -sf uac_auth_audio.xml -r 1 -d 5000 -s 5000 -i 192.168.5.42 192.168.5.151
160 | -r 1
161 | ```
162 |
163 | This is the number of calls to start every second, it can be changed while the test it running.
164 |
165 | `-d 1000`
166 |
167 | This is how long each call should remain up, in milliseconds.
168 |
169 | `-s 5000`
170 |
171 | This is is the number to call, in this case the default check voicemail feature code.
172 |
173 | `-i 192.168.5.42`
174 |
175 | This is the IP address to bind to, you will need to set this to the IP of the server running **SIPp**.
176 |
177 | `192.168.5.151`
178 |
179 | This is the IP address of the **FreeSWITCH** server to test.
180 |
181 | Change the two IP address to be the address of the test server and the address of a **FreeSWITCH** server (in that order).
182 | When you run this test it will round robin between the SIP credentials in `users.csv` running the test `uac_auth_audio.xml`.
183 |
184 | To start the test type:
185 |
186 | `$ ./leave_vm.sh`
187 |
--------------------------------------------------------------------------------
/doc/config/css-custom.md:
--------------------------------------------------------------------------------
1 | Customizing CSS and Colors
2 |
3 | Customizing Default Apps
4 |
5 |
--------------------------------------------------------------------------------
/doc/config/dns_concepts.md:
--------------------------------------------------------------------------------
1 | ## DNS Concepts
2 |
3 |
4 |
5 | ## What is DNS and why do you need to know:
6 |
7 |
8 | ## What
9 |
10 | Short for Domain Name System (or Service or Server), an Internet service that translates domain names into IP addresses. Because domain names are alphabetic, they're easier to remember. The Internet however, is really based on IP addresses. Every time you use a domain name, therefore, a DNS service must translate the name into the corresponding IP address. For example, the domain name www.example.com might translate to `198.105.232.4`. The DNS system is, in fact, its own network. If one DNS server doesn't know how to translate a particular domain name, it asks another one, and so on, until the correct IP address is returned.
11 |
12 |
13 | ## Why
14 |
15 | To be able to connect to our platform u would need to remember ip addreses, To see the GUI go to `88.25.25.1`, register your phone at `89.25.36.2` and so on. You remember kazoo.io and DNS translates that to the proper IP.
16 |
17 |
18 | ## Thats all?
19 |
20 | Nope.. DNS is awesome as it can do some tricks that really help. Here are a few, add more if you like:
21 |
22 | CNAME records >> They enable you to use your own domainname, but still use a hosted GUI thats not at your own IP or server (a bit like masquerading)
23 |
24 | SRV records >> one of the magic tools that **Kazoo** utilizes. It enables you to specify multiple ip adresses for a single service that maybe delivered by one or more servers. Lets say u have a VoiP service, It runs on a single server and you use my-awesome-domain.com. You grow, get smart and need to add an extra server to your system to share load.
25 |
26 | You have no desire to say to 50% of your clients that they need to register to an other server such as im-growing.my-awesome-domain.com.
27 | SRV solves that for you by giving you the ability to use my-awesome-domain.com but have two ip addreses beneath that.
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/doc/config/email-templates.md:
--------------------------------------------------------------------------------
1 | Activation Email
2 | Voicemail to Email
3 | Low Balance Email
4 |
5 |
--------------------------------------------------------------------------------
/doc/config/global-resources.md:
--------------------------------------------------------------------------------
1 | ## GLOBAL RESOURCES
2 |
3 |
4 |
5 | Creating carriers to route outbound calls has never been easier! A single doc for each carrier inside the offnet/ database will make a carrier available to all customers. (Individual customers can optionally set their own carriers in the APIs or via a GUI)
6 | The base doc is pretty simple at this level. Just create a new doc:
7 |
8 | `{_id: random_doc_id, name:my carrier}`
9 |
10 | ## A Carrier
11 |
12 |
13 | Defining a carrier for the system is relatively simple. The keys required are `enabled`, `flag`, `weight_cost`, `route`, and `gateway`:
14 |
15 | `enabled` // toggles whether the carrier is to be included when deciding how to route an outbound call.
16 |
17 | `flag` // a list of features a carrier supports (like CName). This list is matched against a Client DID's options; if all of the features in a DID's options list exist in the carrier's flags, the carrier is kept in the available routes; otherwise it is removed from contention.
18 |
19 | `weight_cost`, when multiple carriers are available to route a call, `weight_cost` allows you to assign which is preferred (by giving it a lower weight). So if you have a primary carrier, assign it 1 (it will be used first).
20 |
21 | `route` // is a list of regular expressions for matching E.164-formatted (+12223334444) DIDs. A sample regex to match all E.164 numbers:
22 | ^\\+1(\\d{10})$
23 | You can add regexes for specific area codes, toll-free, E911, and international numbers. The first capture group is what is used to pass in the bridge URI (in the example, the 10-digit number will be passed to the gateways).
24 |
25 | `gateway` // a list of gateways provided by the carrier that will handle the routes matched by the regex(s).
26 |
27 | `callerid_type` // an optional field that can toggle how CallerID is passed to the carrier. Potential values are `rpid`, `pid`, and from (corresponding to Remote Party ID, P-*-Identity headers, and From).
28 |
29 | `formatter` // an optional object of formatting instructions for inbound requests from the carrier.
30 | ```
31 | {_id:5bbc699c76df9da56363233dcc1214bd, pvt_type:resource, name:Some Carrier, enabled:true, flags:[ ],
32 | weight_cost: 30,
33 | rules: [^\\+1(\\d{10})$],
34 | gateways: [... see below ...],
35 | grace_period: 5,
36 | formatters: {request: [ {regex: ^\\+?1?\\d{6}(\\d{4})$,
37 | prefix: ,suffix: }]}
38 | }
39 |
40 | ```
41 |
42 | ## Gateways
43 |
44 |
45 | Each gateway has a simple configuration that offers enough flexibility for most carriers.
46 | The only two required fields are server and enabled, but a host of other parameters are available to tweak the setup:
47 |
48 | `server` // hostname or IP of the gateway
49 |
50 | `enabled` // is this gateway available to route over.
51 |
52 | `username` // if the gateway requires a username
53 |
54 | `password` // if the gateway requires a password
55 |
56 | `prefix` // if the gateway requires a prefix on the capture group from the succeeding regex
57 |
58 | `suffix` // if the gateway requires a suffix on the capture group
59 |
60 | `codecs` // a list of codecs to constrain the carrier to during negotiation
61 |
62 | `progress_timeout` // the number of seconds to wait for the gateway to connect the call before failing to the next gateway
63 | To clarify the prefix/suffix/capture group, the route sent to the switch will be built as follows:
64 |
65 | `DID +12223334444` is being called, and the above `regex` is matched. The capture group becomes `2223334444`. If prefix or suffix are not set, they default to, the empty string. The resulting INVITE will look like `PREFIXcapture_groupSUFFIX@SERVER` where the text in caps correspond to the fields above.
66 |
67 | ```
68 | gateways: [
69 | {server: sip001.server.voip_carrier.com
70 | ,username:myacctid
71 | ,password:12345
72 | ,prefix:1717
73 | ,suffix:codecs: [ G729, PCMU, ... ]
74 | ,progress_timeout: 8 // 8 seconds
75 | ,enabled: true
76 | }
77 | ]
78 | ```
79 |
80 | ## Bringing it together
81 |
82 |
83 | Here's the stitched-together carriers document:
84 | ```
85 | {_id: 5bbc699c76df9da56363233dcc1214bd
86 | ,pvt_type:resource
87 | ,name:Some Carrier
88 | ,enabled: true
89 | ,flags: [
90 | ,weight_cost: 3
91 | ,rules: [^\\+1(\\d{10}) ]
92 | ,gateways: [
93 | {server:sip.carrier.com
94 | ,realm: sip.carrier.com
95 | ,username:username
96 | ,password: password
97 | ,prefix:+
98 | ,suffix:
99 | ,codecs: [ ]
100 | ,enabled: true
101 | }]
102 |
103 | ,grace_period: 5
104 | ,formatters: {request: [ {regex: ^\\+?1?\\d{6}(\\d{4})$
105 | ,prefix:
106 | ,suffix:
107 | }]
108 |
109 | ]
110 |
111 | }
112 | ```
113 |
114 | A carrier is defined. The first has a route that matches E.164 numbers (so US numbers only). The second carrier will match any number starting with 011 or any number that starts with +2-9 (not +1XXXX..., so no US numbers).
115 |
116 |
117 |
--------------------------------------------------------------------------------
/doc/config/kazoo-config.md:
--------------------------------------------------------------------------------
1 | ## Kazoo Config
2 |
3 |
4 | ```
5 | ; config.ini sample
6 | ; section are between [] = [section]
7 | ; key = value
8 | ; to comment add ";" in front of the line
9 |
10 |
11 | ; EXAMPLE
12 | [amqp]
13 | uri = "amqp://guest:guest@localhost:5672"
14 |
15 | [bigcouch]
16 | compact_automatically = true
17 | cookie = change_me
18 | ip = "localhost"
19 | port = 5984
20 | ; username = "XXX"
21 | ; password = "XXX"
22 | admin_port = 5986
23 |
24 | [log]
25 | syslog = info
26 | console = notice
27 | file = error
28 | ```
29 |
--------------------------------------------------------------------------------
/doc/config/kazoo-mediastream.md:
--------------------------------------------------------------------------------
1 | ## Media Streaming
2 |
3 |
4 |
5 | ## Media Anywhere
6 |
7 | Running a PBX, call center, and other telephony-related applications requires custom media files to be accessible to the softswitch processing the call(s). Music-on-hold (MOH), voicemails, auto-attendant menus, etc, are generally created by either the service provider or customers, and any underlying switch in the **Whistle** platform needs access to those files. Copying all media files to all possible servers is not a viable solution.
8 |
9 |
10 | ## What Do You Do? Here's What We Did:
11 |
12 | We store media binary data in **CouchDB** documents as attachments, with the meta-data of the file the properties of the document itself. When **Whistle** receives a request from a **WhApp** to play custom media, Whistle makes a request to any listening **WhApps** for a URL to stream the media from, and the responding **WhApp** (if any, and usually **MediaMgr**) responds with one of two types of URLs, `shout://` and `http://`.
13 | `shout://`
14 |
15 | A URL prepended by `shout://` indicates MP3 media which **FreeSWITCH** plays via mod_shout. **MediaMgr**, when it sees that the requested media is MP3 data, creates a tiny **SHOUTCast** server to stream the MP3 data and a unique URL that is sent back to **Whistle**. **Whistle** feeds this URL to **FreeSWITCH** which then connects to the stream and plays the audio.
16 | http://
17 |
18 | A URL prepended by `http://` indicates WAV media. Recently, **FreeSWITCH** has added a new module, `mod_shell_stream`, to stream audio from an arbitrary shell command. Combined with a simple sox command, any http URL becomes streamable to **FreeSWITCH**. **MediaMgr** returns an http URL from which it proxies the WAV media from **CouchDB** to **FreeSWITCH**.
19 |
20 |
21 | ## Types of Streams
22 |
23 | Currently we have two streams, new and extant. When **Whistle** requests media data, it indicates whether this is a one-off request (like playing a voicemail) or if it should be joining an already-running stream (like MOH). For one-off requests, "new" is used; for running streams, "extant" is used. If this is the first time the media is requested on an extant stream, the stream is initialized and streaming begun.
24 |
25 |
26 | ## Location Awareness
27 | Sometimes **Whistle** receives a request to play custom media early enough in the Dialplan that **Whistle** can pre-fetch the appropriate URL stream. When this is the case, **Whistle** can wait on several responses from different **MediaMgr** **WhApps** and figure out which is the most appropriate to stream the media from (all media streams in MediaMgr have timeouts, so unused streams will be reclaimed fairly quickly). When rushed, **Whistle** assumes the first responding **WhApp** corresponds to which **WhApp** can also stream the media most efficiently.
28 |
--------------------------------------------------------------------------------
/doc/config/limits/commands.md:
--------------------------------------------------------------------------------
1 | Limits : SUP Commands
2 |
3 |
--------------------------------------------------------------------------------
/doc/config/limits/concepts.md:
--------------------------------------------------------------------------------
1 | Limits : Concepts
2 |
3 | How limits work...
4 | Enabling limits:
5 | Ensure the default values are appropriate in system_config/jonny5
6 | And those are....
7 | Ensure jonny5 is configured to start in system_config/whapps_controller
8 | Ensure jonny5 is running
9 | Ensure you have a "default_to" email address in system_config/notify.system_alert to receive notices
10 | Set "authz_enabled" to true on system_config/ecallmgr
11 | Set "authz_default_action" to either "allow" or "deny" on system_config/ecallmgr. This is used when jonny5 fails to reply.
12 | If you just want to test (and not actually limit) set "authz_dry_run" to true on system_config/ecallmgr.
13 | LikeBe the first to like this
14 |
--------------------------------------------------------------------------------
/doc/config/limits/config.md:
--------------------------------------------------------------------------------
1 | Limits : Config
2 |
3 |
--------------------------------------------------------------------------------
/doc/config/lineman-expect.md:
--------------------------------------------------------------------------------
1 | ## Lineman Expect
2 |
3 |
4 |
5 | The lineman expect tool is a way of defining an expected response from any of the other tools. This is done by binding to events and specifying the expected value.
6 |
7 | ## Toolbag
8 |
9 | This tool has no configuration parameters.
10 |
11 |
12 | ## Sequence Elements
13 |
14 | All sequence elements are in a expect element and described by the type attribute, which defaults to line if not present. This section will be broken down by the available types (more will be added). For the available bindings see the other tool pages.
15 |
16 | `expect[@type='line']`
17 |
18 | Compares the expected content with the binding content line by line. This comparison is implemented by searching for the existence of each line of the expected content in the entire binding content. Failure to find any line or receive content in the defined timeout will fail the current sequence.
19 |
20 | Attribute / Description / Type
21 |
22 | The value can be line or not present binding. The binding that should carry the expected content timeout. The time in milliseconds to wait for a binding content, defaults to 1000.
23 |
24 | `clean` if this is set to `false` then the XML value will not be cleaned up. See **Lineman Test Tool** for details.
25 |
26 | Example:
27 | ```
28 | ?xml version=1.0
29 | encoding=ISO-8859-1?
30 | workorder
31 | sequences
32 | sequence
33 | expect binding= freeswitch.fetch_reply.36889abf-8e1b-498e-9f68-d9ad6af3df48
34 | timeout=2000
35 | ![CDATA[
36 | section name= directory
37 | domain name=test.2600hz.com
38 | user id=device_1
39 | params
40 | param name=password
41 | value= 123456//params
42 | variables
43 | variable name=
44 | ecallmgr_Authorizing-ID
45 | value= e00816343ee126968a5f18a0aa2442e4
46 | variable name= ecallmgr_Inception
47 | value= on-net
48 | variable name=ecallmgr_Authorizing-Type
49 | value=device
50 | variable name=ecallmgr_Account-ID
51 | value=c0705d7474ea0160c10a351b2544006b
52 | variable name=ecallmgr_Realm
53 | value=test.2600hz.com
54 | variable name=ecallmgr_Username
55 | value=device_1
56 | /variable/user/domain/section
57 |
58 | ]]
59 |
60 |
61 | /expect/sequence/sequences/workorder
62 | ``
63 |
--------------------------------------------------------------------------------
/doc/config/lineman-os.md:
--------------------------------------------------------------------------------
1 | ## Lineman OS
2 |
3 |
4 |
5 | This tool executes a operating system command. It can optionally publish the result on a binding so the except tool can compare the result.
6 |
7 |
8 | ## Toolbag
9 |
10 | This tool has no configuration parameters.
11 |
12 |
13 | ## Sequence Elements
14 |
15 | The only sequence element this tool provides is:
16 |
17 | OS
18 |
19 | Attribute
20 |
21 | Description
22 |
23 | Event
24 |
25 | An option event, if specified will be used as the routing key to publish the returned content of the command. Dont forget that sequences run in parallel, use the variables tool to give the event attribute a unique name or your consumers might not be getting the content from this sequence's execution!
26 |
27 | Example:
28 | ```
29 | ?xml version=
30 | 1.0
31 | encoding=
32 | ISO-8859-1
33 | ?
34 | workorder
35 | øsequences
36 | sequence
37 | os event=
38 | os_command.registrar.local_summary
39 | ![CDATA[
40 | /opt/whistle/2600hz-platform/utils/command_bridge/command_bridge registrar_maintenance local_summary test.2600hz.com device_1
41 | ]]
42 | /os
43 | /sequence
44 | /sequences
45 | /workorder
46 | ```
47 |
--------------------------------------------------------------------------------
/doc/config/lineman-test.md:
--------------------------------------------------------------------------------
1 | ## Overview
2 |
3 |
4 |
5 | **Lineman** is a utility for validation and load testing the entire **Whistle** platform. Once complete this tool will be able to simulate **FreeSWITCH** nodes as well as **BigCouch** allowing full integration testing with mixed component fixtures. **Lineman** is a modular architecture with three main components:
6 |
7 | **Workorder** - This are a XML representation of a simulation or load test.
8 |
9 | **Toolbag** - This is a collection of tools (or test components) that are available for use in a workorder.
10 |
11 | **Sequences** - This is a set of directives utilizing lineman tools to preform a test or simulation.
12 |
13 | **Workorder**
14 |
15 | A workorder is an XML file that describes the configuration of the lineman tool, data fixtures, and test procedures. Each workorder defines these three sections as follows:
16 | ```
17 | ?xml version=
18 | 1.0
19 | encoding=
20 | ISO-8859-1
21 | ?
22 |
23 | workorder
24 | parameters
25 | .../parameters
26 |
27 | toolbag
28 | .../toolbag
29 |
30 | sequences
31 | .../sequences/workorder
32 | ```
33 |
34 | *Each section will be detailed below*
35 |
36 | ## Parameters
37 |
38 | Parameters element is used to configure lineman for execution of a workorder, this includes how many simultaneous sequences to run at what rate. The available parameters are:
39 |
40 |
41 | ## Element
42 |
43 |
44 | ## Attributes
45 |
46 |
47 | ## Default
48 |
49 |
50 | ## Description
51 |
52 |
53 | ## Name
54 |
55 |
56 | **Unknown** - This is used for display and logging purposes as a descriptive name of for the workorder:
57 |
58 | `max-running-sequences`
59 |
60 | **100** - The maximum simultaneous running sequences that should be allowed:
61 |
62 | `max-sequence-executions`
63 |
64 | **100** - The maximum number of sequences to execute. The test will stop when this is reached. It is not an absolute value as additional sequences can execute depending on the rate/period parameters:
65 |
66 | `sequence-order`
67 |
68 | **sequential** - If a workorder contains multiple sequences this determines the order that they are executed. Currently the only valid options are:
69 |
70 | `sequential`
71 |
72 | `random`
73 |
74 | `sequence-period`
75 |
76 |
77 | **1000** - A period in milliseconds to execute another set of sequences. Every `sequence-period` starts `sequence-rate` sequences:
78 |
79 | `sequence-rate`
80 |
81 | **1** - The number of sequences to start every `sequence-period`:
82 |
83 | `display-period`
84 |
85 | **2000** - A period in milliseconds to display the current lineman status. The lineman status will always be show at the completion of a workorder.
86 |
87 | **Toolbag** - The toolbag element is were each tool is configure prior to starting execution of the sequences. This section will be processed when the workorder is first loaded, once. See the individual tool pages for details about the XML elements of this section.
88 |
89 | **Sequences** - The sequences element should contain one or more sequence elements. At the end of the `sequence-period` a sequence element will be selected based on the `sequence-order` and execution started, for `sequence-rate` elements each period. If the `sequence-order` is sequential then each sequence element will be started after the previous, in parallel. However, if the `sequence-order` is
90 | random then one of the sequence elements will be chosen at random for execution during the start phase.
91 |
92 | **Tools**
93 |
94 | 1. FreeSWITCH
95 | 2. Expect
96 | 3. Variables
97 | 4. OS
98 | 5. Sleep
99 |
100 | ...more soon
101 |
102 | ## XML Value Cleaning
103 |
104 | By default all XML element values will be cleaned. This is a process by which leading whitespace is stripped from all lines as well as the first and last newline of only whitespace. This allows the element value to be tabified and on the lines between the open/close XML tags. However, if the value is sensitive to this process any element can define set a clean attribute to `false` and this process will be skipped.
105 |
106 | 1. Example Workorders
107 | 2. Load Testing Registrar
108 | 3. Registrar Validation
109 |
110 | ...more soon
111 |
--------------------------------------------------------------------------------
/doc/config/milliwatt-config.md:
--------------------------------------------------------------------------------
1 | ## Milliwatt Configuration
2 |
3 |
4 |
5 | Create a document (with `milliwatt` for `id`) in the `system_config` database.
6 |
7 |
8 | ## Base Parameters
9 | ```
10 | echo
11 | duration
12 | ```
13 | This sets the duration of the echo action. The value is in milliseconds.
14 |
15 | Sample Code:
16 | ```
17 | duration: 5000
18 | caller_id
19 | ```
20 |
21 | This sets the caller ids of the echo action. It means that any call made from theses numbers (or users) will be redirected to Milliwatt echo action.
22 |
23 | Sample Code:
24 | ```
25 | caller_id: [4155555555, username]
26 | number
27 | ```
28 |
29 | This sets the number of the echo action. It means that any call made
30 | to these numbers will be redirected to Milliwatt echo action.
31 |
32 | Sample Code:
33 |
34 | `number: [123456789,1011121314]`
35 |
36 | Sample Code
37 | ```
38 | echo: {duration : 5000
39 | ,caller_id: [
40 | 4155555555,username
41 | ],
42 |
43 | number: [123456789]}
44 | tone
45 | frequencies
46 | ```
47 |
48 | This sets the frequencies used for the tone action.
49 |
50 | Sample Code
51 | ```
52 | frequencies: [2600, 2300]
53 | duration
54 | ```
55 |
56 | This sets the duration of the tone action. The value is in milliseconds.
57 |
58 | Sample Code
59 | ```
60 | duration: 5000
61 | caller_id
62 | ```
63 | This sets the caller ids of the tone action. It means that any call made from theses numbers (or users) will be redirected to Milliwatt tone action.
64 |
65 | Sample Code
66 | ```
67 | caller_id: [4155555555, username]
68 | number
69 | ```
70 |
71 | This sets the number of the tone action. It means that any call made to these numbers will be redirected to Milliwatt tine action.
72 |
73 | Sample Code
74 | ```
75 | number: [
76 | 123456789,1011121314]
77 | ```
78 |
79 | Sample Code
80 | ```
81 | tone: {
82 | frequencies: [2600]
83 | ,duration: 5000
84 | ,caller_id: [4155555555
85 | ,username
86 | ]
87 | ,number: [123456789]
88 | }
89 | ```
90 |
91 | Sample Code:
92 | ```
93 | {_id: milliwatt,default: {echo: {duration
94 | : 5000
95 | ,caller_id: [username_echo ],
96 |
97 | number: [5555555551]
98 | }
99 | ,tone: {frequencies:[2600]
100 | ,duration: 2000
101 | ,caller_id: [username_tone]
102 | ,number: [5555555552]
103 | }
104 | }
105 | }
106 | ```
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/doc/config/monitor-maintain.md:
--------------------------------------------------------------------------------
1 | ## Monitor Maintain Whistle_Apps
2 |
3 |
4 |
5 | Connect to the Erlang `whistle_apps` shell:
6 |
7 | `whistle_apps/conn-to-apps.sh`
8 |
9 | Flushing the cache (callflows, CID, ect):
10 |
11 | `wh_cache:flush().`
12 |
13 | Flushing the `config` (db cached system config) requires restart of `sysconf whapp`:
14 | ```
15 | whapps_config:flush().
16 | whapps_controller:restart_app(sysconf).
17 | ```
18 |
19 | **Erlang**-based Application list (full):
20 |
21 | `application:which_applications().`
22 |
23 | Start, stop **WhApps** and verify running **WhApps**:
24 | ```
25 | whapps_controller:start_app(crossbar).
26 | whapps_controller:stop_app(crossbar).
27 | whapps_controller:running_apps().
28 | ```
29 |
30 | Determine which **CouchDB/BIGCouch** server it is connected to
31 | ```
32 | couch_mgr:get_host().
33 | couch_mgr:get_creds().
34 | ```
35 |
36 | Forcing Compaction
37 | ```
38 | couch_compactor:start_link().
39 | couch_compactor:force_compaction().
40 | ```
41 |
42 | Determine which **RabbiMQ** you are connecting to:
43 | ```
44 | amqp_mgr:get_host().
45 | amqp_mgr:is_available().
46 | ```
47 |
48 | **Stepswitch** Commands
49 | ```
50 | stepswitch_maintenance:reconcile().
51 | stepswitch_maintenance:reconcile(ACCOUNT_ID).
52 | stepswitch_maintenance:reload_resources().
53 | stepswitch_maintenance:lookup_number(5552223333).
54 | stepswitch_maintenance:process_number(5552223333).
55 | ```
56 |
57 | **Whapps** Maintenance (useful for updating the global views in **BigCouch** on an install)
58 | ```
59 | whapps_maintenance:refresh().
60 | whapps_maintenance:refresh(Account ID).
61 | ```
62 |
63 | NOTE - THIS REPLACED:
64 |
65 | `crossbar:refresh().`
66 |
67 | Callflow Refresh Command (useful for after upgrade)
68 |
69 | `callflow_maintenance:refresh().`
70 |
71 | Whistle Number Manager (iterates thru each account checking all DID's exist in the numbers db)
72 |
73 | `whistle_number_manager_maintenance:reconcile().`
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/doc/config/registrar-design.md:
--------------------------------------------------------------------------------
1 | ## Register Startup
2 |
3 |
4 | 1. On startup of Registrar, prime the cache by looking up the registrations currently stored in the DB Registration Attempt.
5 | 2. Phone sends registration to SBC, which load-balances the request to the next switch in its list.
6 | 3. Switch sends an auth challenge back
7 | 4. Phone sends registration with digest data
8 | 5. Switch forwards request to Whistle
9 | 6. **Whistle** creates an `authn_req`AMQP message
10 | 7. Registrar receives `authn_req` AMQP message
11 | 8. If credentials are found, Registrar sends an `authn_resp` AMQP message
12 | 9. **Whistle** receives the response and sends the switch the appropriately formatted response.
13 | 10. Phone is notified of success or failure
14 | 11. Using the `Auth-User` and `Auth-Realm`, lookup the sip credentials for this combination
15 | 12. Check the in-memory cache for the sip credential object.
16 | 13. If found, return the object else, lookup in the DB for the user/realm combination and cache the response
17 | 14. If the user/realm isn't found, this process stop processing immediately
18 | 15. Create the `authn_resp` AMQP message
19 | 16. Send it directly to the requesting **Whistle** process
20 | 17. The phone is now registered (or not). Behind the scenes, there is more to be done though. **Whistle**, upon learning of a successful registration, will create a `reg_success` AMQP message for which Registrar is also listening. Upon receipt:
21 | 18. Cleanup the contact string
22 | 19. Create the cache ID from the contact string (md5'ed)
23 |
24 | ## Lookup in the cache:
25 |
26 | 1. If the cache ID exists: update the cache with the latest registration JSON object.
27 | 2. If it doesn't exist: remove the old registrations for the username/realm from the database.
28 | 3. Store the registration in the cache and a mapping of username/realm to the cache ID.
29 | 4. Store the registration in the database.
30 |
31 |
32 | ## Querying the Registrar
33 |
34 | 1. Sending a `reg_query` on AMQP is picked up by Registrar
35 | 2. Using the username/realm, lookup the registration cache ID.
36 | 3. If the cache ID exists, lookup the registration JSON object.
37 | 4. If the cache ID doesn't exist, the process exits.
38 | 5. Based on what Fields are requested in the query, a response is created from the cached registration JSON.
39 |
40 |
41 | ## MISC
42 |
43 | The Registration/Authentication **WhApp**, responsible for receiving auth/reg events off AMQP from `ecallmgr`, querying a SIP credentials DB, and returning a response to AMQP on successful lookup. A registration doc will also be created/updated on success (may need to figure out how nonce/cnonce work for verifying the password).
44 |
45 | **Registration Success Message**
46 |
47 | **Event-Category** `directory` required
48 |
49 | **Event-Name** `reg_success` required
50 |
51 | **Event-Timestamp** `timestamp` required
52 |
53 | **From-User** `username` required
54 |
55 | **From-Host** `host.com` required
56 |
57 | **Contact** `contact@host.com:1234;other=params` required
58 |
59 | **RPid** unknown, maybe others required
60 |
61 | **Status** some status optional
62 |
63 | **Expires** time,in seconds required
64 |
65 | **To-User** `username` required
66 |
67 | **To-Host** 1.2.3.4 required
68 |
69 | **Network-IP** 1.2.3.4 required
70 |
71 | **Network-Port** 12345 required
72 |
73 | **Username** `username` required
74 |
75 | **Realm** 1.2.3.4 required
76 |
77 | **User-Agent** Whistle-1.0 optional
78 |
79 |
80 | ## Querying the Registration WhApp
81 |
82 | Given user credentials, you can retrieve the fields listed above in the 'Registration Success' message for any registrations that have not expired.
83 |
84 | **Event-Category** directory required
85 |
86 | **Event-Name** `reg_query` required
87 |
88 | **Username** string required
89 |
90 | **Realm** string required
91 |
92 | **Fields** `[whistle:Field]` required
93 |
94 |
95 | Your application will receive the following message as response:
96 |
97 | **Event-Category** directory required
98 |
99 | **Event-Name** `reg_query_resp` required
100 |
101 | **Fields** `[whistle:{Field, Value}]` required
102 |
--------------------------------------------------------------------------------
/doc/config/ssl/.org/easy_setup.org:
--------------------------------------------------------------------------------
1 | #+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:{} arch:headline
2 | #+OPTIONS: author:t broken-links:nil c:nil creator:nil
3 | #+OPTIONS: d:(not "LOGBOOK") date:t e:t email:nil f:t inline:t num:t
4 | #+OPTIONS: p:nil pri:nil prop:nil stat:t tags:t tasks:t tex:t
5 | #+OPTIONS: timestamp:t title:t toc:t todo:t |:t
6 | #+TITLE: Easy Setup of SSL
7 | #+DATE: <2016-11-21 Mon>
8 | #+AUTHOR: James Aimonetti
9 | #+EMAIL: james@2600hz.com
10 | #+LANGUAGE: en
11 | #+SELECT_TAGS: export
12 | #+EXCLUDE_TAGS: noexport
13 | #+CREATOR: Emacs 26.0.50.1 (Org mode 9.0)
14 |
15 | * Quick SSL Setup Guide
16 |
17 | This guide assumes you have configured your DNS properly to point to the server you wish to secure. It will assume you are using Apache to serve MonsterUI and as a reverse proxy for Crossbar (the API server) for SSL termination.
18 |
19 | ** Let's Encrypt Cert Setup
20 |
21 | We'll use [[https://letsencrypt.org/][Let's Encrypt]] to generate a free SSL certificate for us. See [[https://www.digitalocean.com/community/tutorials/how-to-secure-apache-with-let-s-encrypt-on-ubuntu-14-04][these instructions]] for a more detailed guide.
22 | #+BEGIN_SRC bash
23 | # First, get the script from EFF
24 | sudo wget -O /usr/local/sbin https://dl.eff.org/certbot-auto
25 |
26 | # Make it executable
27 | sudo chmod a+x /usr/local/sbin/certbot-auto
28 | #+END_SRC
29 |
30 | *** Setup Let'sEncrypt and Apache
31 |
32 | To start an interactive session to setup the certificate for your domain (in this case, kazoo.mycompany.com):
33 |
34 | #+BEGIN_SRC bash
35 | certbot-auto --apache -d kazoo.mycompany.com
36 | #+END_SRC
37 |
38 | Certificates will be installed to `/etc/letsencrypt/live`
39 |
40 | *** Auto-renew
41 |
42 | Let's Encrypt certificates are valid for 90 days. Triggering the renewal process is straight-forward:
43 |
44 | #+BEGIN_SRC bash
45 | certbot-auto renew
46 | #+END_SRC
47 |
48 | Setup auto-renewal in the form of a cronjob:
49 |
50 | #+BEGIN_SRC bash
51 | sudo crontab -e
52 | #+END_SRC
53 |
54 | #+BEGIN_SRC crontab
55 | 30 2 * * 1 /usr/local/sbin/certbot-auto renew >> /var/log/le-renew.log
56 | #+END_SRC
57 | ** Setup Apache as a reverse proxy
58 |
59 | Having Apache (or any HTTP server) proxy the requests for the API server makes sense. You can manage your certificates in fewer places and API servers can come and go since each request is independent of any others (no state shared between requests on a given API server).
60 |
61 | We create two VirtualHost entries, one for serving MonsterUI assets and one for proxying to Crossbar.
62 | *** MonsterUI
63 | #+BEGIN_SRC apache
64 |
65 | ServerName kazoo.mycompany.com:443
66 |
67 | DocumentRoot /var/www/html/monster-ui
68 |
69 | SSLEngine on
70 | SSLCertificateKeyFile "/etc/letsencrypt/live/kazoo.mycompany.com/privkey.pem"
71 | SSLCertificateFile "/etc/letsencrypt/live/kazoo.mycompany.com/cert.pem"
72 |
73 |
74 | #Options FollowSymLinks
75 | Options Indexes FollowSymLinks Includes ExecCGI
76 | AllowOverride All
77 | Order deny,allow
78 | Allow from all
79 |
80 |
81 | #+END_SRC
82 | *** API Reverse Proxy
83 | Be sure to replace the IPs with the IP Crossbar is using.
84 | #+BEGIN_SRC apache
85 |
86 | ServerName kazoo.mycompany.com:8443
87 | ProxyPreserveHost On
88 |
89 | SSLEngine on
90 | SSLCertificateKeyFile "/etc/letsencrypt/live/pdx.2600hz.com/privkey.pem"
91 | SSLCertificateFile "/etc/letsencrypt/live/pdx.2600hz.com/fullchain.pem"
92 |
93 | ProxyPass / http://10.1.10.29:8000/
94 | ProxyPassReverse / http://10.1.10.29:8000/
95 |
96 | #+END_SRC
97 |
98 | *** Reconfigure MonsterUI and the Apps
99 |
100 | Once you've reloaded Apache, you'll want to update MonsterUI's config.js:
101 |
102 | #+BEGIN_SRC bash
103 | vim /var/www/html/monster-ui/js/config.js
104 | # Update api_url to 'https://kazoo.mycompany.com:8443/v2'
105 | #+END_SRC
106 |
107 | And re-init the apps:
108 | #+BEGIN_SRC bash
109 | # Re-initialize Monster Apps
110 | sup crossbar_maintenance init_apps \
111 | /var/www/html/monster-ui/apps \
112 | https://kazoo.mycompany.com:8443/v2
113 | #+END_SRC
114 |
--------------------------------------------------------------------------------
/doc/config/ssl/easy_setup.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Quick SSL Setup Guide
4 |
5 | This guide assumes you have configured your DNS properly to point to the server you wish to secure. It will assume you are using Apache to serve MonsterUI and as a reverse proxy for Crossbar (the API server) for SSL termination.
6 |
7 |
8 |
9 |
10 | ## Let's Encrypt Cert Setup
11 |
12 | We'll use [Let's Encrypt](https://letsencrypt.org/) to generate a free SSL certificate for us. See [these instructions](https://www.digitalocean.com/community/tutorials/how-to-secure-apache-with-let-s-encrypt-on-ubuntu-14-04) for a more detailed guide.
13 |
14 | ```bash
15 | # First, get the script from EFF
16 | sudo wget -O /usr/local/sbin https://dl.eff.org/certbot-auto
17 |
18 | # Make it executable
19 | sudo chmod a+x /usr/local/sbin/certbot-auto
20 | ```
21 |
22 |
23 |
24 |
25 | ### Setup Let'sEncrypt and Apache
26 |
27 | To start an interactive session to setup the certificate for your domain (in this case, kazoo.mycompany.com):
28 |
29 | ```bash
30 | certbot-auto --apache -d kazoo.mycompany.com
31 | ```
32 |
33 | Certificates will be installed to \`/etc/letsencrypt/live\`
34 |
35 |
36 |
37 |
38 | ### Auto-renew
39 |
40 | Let's Encrypt certificates are valid for 90 days. Triggering the renewal process is straight-forward:
41 |
42 | ```bash
43 | certbot-auto renew
44 | ```
45 |
46 | Setup auto-renewal in the form of a cronjob:
47 |
48 | ```bash
49 | sudo crontab -e
50 | ```
51 |
52 | ```crontab
53 | 30 2 * * 1 /usr/local/sbin/certbot-auto renew >> /var/log/le-renew.log
54 | ```
55 |
56 |
57 |
58 |
59 | ## Setup Apache as a reverse proxy
60 |
61 | Having Apache (or any HTTP server) proxy the requests for the API server makes sense. You can manage your certificates in fewer places and API servers can come and go since each request is independent of any others (no state shared between requests on a given API server).
62 |
63 | We create two VirtualHost entries, one for serving MonsterUI assets and one for proxying to Crossbar.
64 |
65 |
66 |
67 |
68 | ### MonsterUI
69 |
70 | ```apache
71 |
72 | ServerName kazoo.mycompany.com:443
73 |
74 | DocumentRoot /var/www/html/monster-ui
75 |
76 | SSLEngine on
77 | SSLCertificateKeyFile "/etc/letsencrypt/live/kazoo.mycompany.com/privkey.pem"
78 | SSLCertificateFile "/etc/letsencrypt/live/kazoo.mycompany.com/cert.pem"
79 |
80 |
81 | #Options FollowSymLinks
82 | Options Indexes FollowSymLinks Includes ExecCGI
83 | AllowOverride All
84 | Order deny,allow
85 | Allow from all
86 |
87 |
88 | ```
89 |
90 |
91 |
92 |
93 | ### API Reverse Proxy
94 |
95 | Be sure to replace the IPs with the IP Crossbar is using.
96 |
97 | ```apache
98 |
99 | ServerName kazoo.mycompany.com:8443
100 | ProxyPreserveHost On
101 |
102 | SSLEngine on
103 | SSLCertificateKeyFile "/etc/letsencrypt/live/pdx.2600hz.com/privkey.pem"
104 | SSLCertificateFile "/etc/letsencrypt/live/pdx.2600hz.com/fullchain.pem"
105 |
106 | ProxyPass / http://10.1.10.29:8000/
107 | ProxyPassReverse / http://10.1.10.29:8000/
108 |
109 | ```
110 |
111 |
112 |
113 |
114 | ### Reconfigure MonsterUI and the Apps
115 |
116 | Once you've reloaded Apache, you'll want to update MonsterUI's config.js:
117 |
118 | ```bash
119 | vim /var/www/html/monster-ui/js/config.js
120 | # Update api_url to 'https://kazoo.mycompany.com:8443/v2'
121 | ```
122 |
123 | And re-init the apps:
124 |
125 | ```bash
126 | # Re-initialize Monster Apps
127 | sup crossbar_maintenance init_apps \
128 | /var/www/html/monster-ui/apps \
129 | https://kazoo.mycompany.com:8443/v2
130 | ```
131 |
--------------------------------------------------------------------------------
/doc/config/ssl/for_api.md:
--------------------------------------------------------------------------------
1 | Configuring SSL for Crossbar
2 |
--------------------------------------------------------------------------------
/doc/config/ssl/for_tls.md:
--------------------------------------------------------------------------------
1 | SSL for TLS
2 |
3 |
--------------------------------------------------------------------------------
/doc/config/ssl/for_wss.md:
--------------------------------------------------------------------------------
1 | SSL for WSS
2 |
3 |
--------------------------------------------------------------------------------
/doc/config/system_config.md:
--------------------------------------------------------------------------------
1 | System Configuration Documents
2 |
--------------------------------------------------------------------------------
/doc/crossbar/api-design.md:
--------------------------------------------------------------------------------
1 | ## Crossbar API Design
2 |
3 |
4 |
5 | ## API Design
6 |
7 | Everyone thinks the APIs are so mysterious so here's a little secret. The APIs are actually a very simple pass-thru mechanism with some logic in the middle:
8 |
9 | Request From Browser --> HTTP Server --> Authentication Check --> Data Validation --> (Some Routing Magic) --> Save to Database (without changing the format of the original request)
10 |
11 | In other words, in almost every API request:
12 |
13 | 1. We read a document from **CouchDB**, in **JSON** format
14 | 2. We strip any fields with `pvt_ and _ at` the beginning of the field names out
15 | 3. We send it to you via the API
16 |
17 | So what's in the DB is what you get back via API calls. And what you send to the API works in reverse but the same - if you send it, we store it. That means if you want to introduce new features, custom fields, etc. well, you can! Just add them to your API requests and change the validation to allow those new fields. The validation criteria is also kept in the database (makes it easy to change) - check out the `system_schemas` database. Add or remove at will.
18 |
19 | The only things layered "in-between" your request and the database are:
20 |
21 | Validation, which is done off configurable documents - check out the `system_schemas` database
22 |
23 | Note: The schemas also allow you to auto-add default values if they are missing, when a document is created or updated
24 |
25 | Authentication. You must have access to the account, based on your `auth_token`
26 |
27 | Eventing. You can listen for events when someone stores or retrieves something
28 |
29 | Some internationalization and upload/binary file handling, in some cases
30 |
31 | A message bus to transport the requests to/from the apps
32 |
--------------------------------------------------------------------------------
/doc/crossbar/authentication.md:
--------------------------------------------------------------------------------
1 | ## Enabling / Disabling Authentication
2 |
3 | Only turn authentication on and/or authorization off on a non-public server. Servers with no authentication can be easily compromised.
4 |
5 | **Kazoo** comes with two modules that allow you to bypass the authentication and authorization mechanisms, but has them turned off by default. Enabling them is relatively easy. These instructions assume the **Crossbar** application is running in the **kazoo_apps** container and is listening on port 8000, the default.
6 |
7 | ## Steps to Turn Off Auth
8 | ```
9 | sup crossbar_module_sup start_mod cb_noauthn
10 | sup crossbar_module_sup start_mod cb_noauthz
11 | ```
12 |
13 | ## What did we just do?
14 |
15 | We just loaded two dummy modules, one for authentication and one for authorization. These modules listen for authentication and authorization requests and blindly reply to them in the affirmative. You must still provide credentials when performing checks on the system, but the credentials (such as a username and password, or an X-Auth-Token) can be bogus.
16 |
17 | ## Turning Auth Back On
18 | ```
19 | sup crossbar_module_sup stop_mod cb_noauthn
20 | sup crossbar_module_sup stop_mod cb_noauthz
21 | ```
22 |
23 | ## What did we just do?
24 |
25 | We just stopped and unloaded the two dummy modules that blindly reply to authentication and authorization requests. You will now be enforcing username/password and auth token requirements as normal.
26 |
27 | To verify the enabling/disabling
28 |
29 | XXXX
30 |
31 |
--------------------------------------------------------------------------------
/doc/crossbar/haproxy.md:
--------------------------------------------------------------------------------
1 | ## HAProxy
2 |
3 |
4 |
5 | *Use HAProxy 1.5 to create an SSL reverse proxy*
6 |
7 | If you're working from an existing install, you will likely need to remove HAProxy 1.4 before continuing. Be sure to take a backup of `/etc/haproxy/haproxy.cfg`!
8 |
9 | `yum erase haproxy`
10 |
11 | We are going to build **HAProxy** from a source `rpm`, so we need to install a few things:
12 |
13 | `yum install @development openssl-devel pcre-static pcre-devel`
14 |
15 | Then we download a source `rpm` to build from:
16 |
17 | `curl -O http://dagobah.ftphosting.net/yum/SRPMS/haproxy-1.5-dev14.src.rpm`
18 |
19 | Then we build the `rpm`:
20 |
21 | `rpmbuild --rebuild haproxy-1.5-dev14.src.rpm `
22 |
23 | Then we install the `rpm` we just built:
24 |
25 | `rpm -Uvh rpmbuild/RPMS/x86_64/haproxy-1.5-dev14.x86_64.rpm`
26 |
27 | Let's move the original config back in place:
28 |
29 | `mv /etc/haproxy/haproxy.cfg.rpmsave /etc/haproxy/haproxy.cfg`
30 |
31 | Let's make a directory for the cert/s:
32 |
33 | `mkdir -p /etc/haproxy/certs`
34 |
35 | Put your `pem` cert/key into the `certs` folder:
36 |
37 | `mv certificate.pem /etc/haproxy/certs`
38 |
39 | Add the following to the `/etc/haproxy/haproxy.cfg config`:
40 |
41 | ```
42 | frontend whapps-ssl-in
43 | bind *:8443 ssl crt /etc/haproxy/certs/certificate.pem
44 | default_backend whapps
45 | backend whapps
46 | balance roundrobin
47 | server localhost host.domain.com:8000 check
48 | ```
49 |
50 | Restart **HAProxy** and enjoy!
51 |
52 |
53 | ## Cleanup:
54 |
55 | Update the `/var/www/html/config/config.js` for the new `https`: and `port`
56 |
57 | You may need to update the endpoint entries for existing users to point to the new `https`: and `port`, you can see how to do that here:
58 |
59 |
60 | ## Manually Editing Database Documents
61 |
62 | **Notes:**
63 |
64 | If you have an existing cert, `ca-bundle` and `key`, here's how you can make the `pem`:
65 |
66 | `cat certificate.crt ca-bundle.crt private.key > certificate.pem`
67 |
68 | Hopefully it's obvious that the paths, and host names need to be updated for your environment.
69 |
--------------------------------------------------------------------------------
/doc/extending/authz.md:
--------------------------------------------------------------------------------
1 | ## Hook Auth Externally
2 |
3 |
4 |
5 | **Kazoo** allows you to hook to authentication and authorization requests externally. This makes it simple to attach a billing or single sign-on system externally. The concept is easy to understand. Each time a username/password needs verification, we'll make a call to your external system to check if it's valid. Each time a phone number is dialed, we'll make a call to your external system to make sure it's OK for the identified customer to make that call.
6 |
--------------------------------------------------------------------------------
/doc/install/.org/configure_kazoo.org:
--------------------------------------------------------------------------------
1 | #+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:{} arch:headline
2 | #+OPTIONS: author:t broken-links:nil c:nil creator:nil
3 | #+OPTIONS: d:(not "LOGBOOK") date:t e:t email:nil f:t inline:t num:t
4 | #+OPTIONS: p:nil pri:nil prop:nil stat:t tags:t tasks:t tex:t
5 | #+OPTIONS: timestamp:t title:t toc:t todo:t |:t
6 | #+TITLE: configure_kazoo
7 | #+DATE: <2016-11-15 Tue>
8 | #+AUTHOR: James Aimonetti
9 | #+EMAIL: james@2600hz.com
10 | #+LANGUAGE: en
11 | #+SELECT_TAGS: export
12 | #+EXCLUDE_TAGS: noexport
13 | #+CREATOR: Emacs 26.0.50.2 (Org mode 9.0)
14 |
15 | * Configuring Kazoo
16 | This guide assumes you've installed Kazoo via one of the supported methods and are now ready to create devices, users, carriers, etc.
17 | ** API Basics
18 | Kazoo requires an auth-token for most API usage. You can create a token via a number of ways but we'll just use the username/password we created in the installation guide.
19 |
20 | #+BEGIN_SRC bash
21 | # User/Pass credentials hash
22 | echo -n "{USERNAME}:{PASSWORD}" | md5sum
23 | {MD5_HASH} -
24 |
25 | # Copy the {MD5_HASH} and create an Auth Token
26 | curl -v -X PUT -H "content-type:application/json" \
27 | -d '{"data":{"credentials":"{MD5_HASH}","account_name":"{ACCOUNT_NAME}"}}' \
28 | http://ip.add.re.ss:8000/v2/user_auth | python -mjson.tool
29 |
30 | # Export the "auth_token" and "account_id" for easy use in later API requests
31 | export AUTH_TOKEN="{AUTH_TOKEN}"
32 | export ACCOUNT_ID="{ACCOUNT_ID}"
33 | #+END_SRC
34 |
35 | Now your shell will have an auth token and account id to use (please export the real values and not the {...} placeholders.
36 | ** Create a device
37 | *** Via API
38 | #+BEGIN_SRC bash
39 | # Create a base device
40 | curl -X PUT -H "X-Auth-Token: $AUTH_TOKEN" \
41 | -d '{"data":{"name":"Device1"}}' \
42 | http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/devices | python -mjson.tool
43 |
44 | # capture the "id" of the device
45 | export DEVICE_ID="{DEVICE_ID}"
46 |
47 | # Add a terrible username and password
48 | curl -X PATCH -H "X-Auth-Token: $AUTH_TOKEN" \
49 | -d '{"data":{"sip":{"username":"device_1","password":"password_1"}}}' \
50 | http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/devices/$DEVICE_ID | python -mjson.tool
51 | #+END_SRC
52 |
53 | Using the realm of the account, you should now be able to register a phone using the credentials created.
54 | *** Via MonsterUI
55 | Use SmartPBX - Screenshots welcomed
56 | ** Create a callflow for the device
57 | *** Via API
58 | #+BEGIN_SRC bash
59 | # create a callflow for extension 1001 to ring the device
60 | # note: we need to escape the quotes to use $DEVICE_ID in the JSON data
61 | curl -X PUT -H "X-Auth-Token: $AUTH_TOKEN" \
62 | -d "{\"data\":{\"name\":\"Device1 Callflow\", \"numbers\":[\"1001\"], \"flow\":{\"module\":\"device\",\"data\":{\"id\":\"$DEVICE_ID\"}}}}" \
63 | http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/callflows | python -mjson.tool
64 | #+END_SRC
65 |
66 | You should now be able to create a second device and call 1001 to ring the first device
67 | ** Create an outbound carrier
68 |
69 | This assumes you have an upstream carrier that uses username/password to authenticate your calls.
70 | #+BEGIN_SRC bash
71 | # Create a "resource" representing the carrier
72 | # "rules" is a list of regexes to match numbers for this carrier
73 | # "gateways" is a list of JSON objects representing the gateway(s) to use
74 | curl -X PUT -H "X-Auth-Token: $AUTH_TOKEN" \
75 | -d '{"data":{"rules":[".{5,}"],"name":"Carrier Foo","gateways":[{"realm":"sip.carrier.com","server":"sip.carrier.com","username":"your_username","password":"your_password","enabled":true}]}}' \
76 | http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/resources | python -mjson.tool
77 |
78 | # capture the id of the resource
79 | export RESOURCE_ID="{RESOURCE_ID}"
80 |
81 | # Now create a callflow to use this account resource
82 | # This uses the "no_match" special number
83 | curl -X PUT -H "X-Auth-Token: $AUTH_TOKEN" \
84 | -d '{"data":{"name":"Offnet Callflow","numbers":["no_match"],"flow":{"module":"resources","data":{"use_local_resources":true}}}}' \
85 | http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/callflows | python -mjson.tool
86 | #+END_SRC
87 |
88 | If you use the regex above, any number 5 digits or more will route to your carrier.
89 | ** Route numbers to your setup
90 |
91 | Getting numbers to route in Kazoo requires a few steps. This guide will use the defaults in the system (read: mostly US-based numbers) to make this fast. Alternative documentation should be created for handling other areas of the world.
92 |
93 | 1. Add the carrier to the ACLs
94 | #+BEGIN_SRC bash
95 | sup ecallmgr_maintenance allow_carrier CarrierFoo 1.2.3.4/32
96 | #+END_SRC
97 | You can set the IP as a raw IPv4 IP address or in [[https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation][CIDR notation]].
98 | 2. Add a number that you expect your carrier to route to you
99 | #+BEGIN_SRC bash
100 | curl -X PUT -H "X-Auth-Token: $AUTH_TOKEN" \
101 | -d '{"data":{}}' \
102 | "http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/phone_numbers/+15551234567" | python -mjson.tool
103 |
104 | # Activate the number
105 | curl -v -X PUT -H "X-Auth-Token: $AUTH_TOKEN" \
106 | -d '{"data":{}}' \
107 | "http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/phone_numbers/+15551234567/activate" | python -mjson.tool
108 | #+END_SRC
109 | 3. Create a callflow for that DID. You could also amend the callflow created for the first device, adding the number to its "numbers" array.
110 | #+BEGIN_SRC bash
111 | curl -X PUT -H "X-Auth-Token: $AUTH_TOKEN" \
112 | -d "{\"data\":{\"name\":\"Main Callflow\",\"numbers\":[\"+15551234567\"],\"flow\":{\"module\":\"device\",\"data\":{\"id\":\"$DEVICE_ID\"}}}}" \
113 | http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/callflows | python -mjson.tool
114 | #+END_SRC
115 | ** Create a PBX
116 | If you have existing PBXes and want to provide them with SIP trunks, create a "connectivity" doc.
117 | Be sure any DIDs you add here have been added in the above method (or similar).
118 | #+BEGIN_SRC bash
119 | curl -X PUT -H "X-Auth-Token: $AUTH_TOKEN" \
120 | -d '{"data":{"account":{"auth_realm":"{ACCOUNT_SIP_REALM}"},"servers":[{"DIDs":{"+12125554321":{}},"options":{"inbound_format":"e164"},"auth":{"auth_method":"password","auth_user":"{USERNAME}","auth_password":"{PASSWORD}"}}]}}'
121 | http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/connectivity
122 | #+END_SRC
123 |
--------------------------------------------------------------------------------
/doc/install/configure_kazoo.md:
--------------------------------------------------------------------------------
1 | # Configuring Kazoo
2 |
3 | This guide assumes you've installed Kazoo via one of the supported methods and are now ready to create devices, users, carriers, etc.
4 |
5 | ## API Basics
6 |
7 | Kazoo requires an auth-token for most API usage. You can create a token via a number of ways but we'll just use the username/password we created in the installation guide.
8 |
9 | ```bash
10 | # User/Pass credentials hash
11 | echo -n "{USERNAME}:{PASSWORD}" | md5sum
12 | {MD5_HASH} -
13 |
14 | # Copy the {MD5_HASH} and create an Auth Token
15 | curl -v -X PUT -H "content-type:application/json" \
16 | -d '{"data":{"credentials":"{MD5_HASH}","account_name":"{ACCOUNT_NAME}"}}' \
17 | http://ip.add.re.ss:8000/v2/user_auth | python -mjson.tool
18 |
19 | # Export the "auth_token" and "account_id" for easy use in later API requests
20 | export AUTH_TOKEN="{AUTH_TOKEN}"
21 | export ACCOUNT_ID="{ACCOUNT_ID}"
22 | ```
23 |
24 | Now your shell will have an auth token and account id to use (please export the real values and not the {…} placeholders.
25 |
26 | ## Create a device
27 |
28 | ### Via API
29 |
30 | ```bash
31 | # Create a base device
32 | curl -X PUT -H "X-Auth-Token: $AUTH_TOKEN" \
33 | -d '{"data":{"name":"Device1"}}' \
34 | http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/devices | python -mjson.tool
35 |
36 | # capture the "id" of the device
37 | export DEVICE_ID="{DEVICE_ID}"
38 |
39 | # Add a terrible username and password
40 | curl -X PATCH -H "X-Auth-Token: $AUTH_TOKEN" \
41 | -d '{"data":{"sip":{"username":"device_1","password":"password_1"}}}' \
42 | http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/devices/$DEVICE_ID | python -mjson.tool
43 | ```
44 |
45 | Using the realm of the account, you should now be able to register a phone using the credentials created.
46 |
47 | ### Via MonsterUI
48 |
49 | Use SmartPBX - Screenshots welcomed
50 |
51 | ## Create a callflow for the device
52 |
53 | ### Via API
54 |
55 | ```bash
56 | # create a callflow for extension 1001 to ring the device
57 | # note: we need to escape the quotes to use $DEVICE_ID in the JSON data
58 | curl -X PUT -H "X-Auth-Token: $AUTH_TOKEN" \
59 | -d "{\"data\":{\"name\":\"Device1 Callflow\", \"numbers\":[\"1001\"], \"flow\":{\"module\":\"device\",\"data\":{\"id\":\"$DEVICE_ID\"}}}}" \
60 | http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/callflows | python -mjson.tool
61 | ```
62 |
63 | You should now be able to create a second device and call 1001 to ring the first device
64 |
65 | ## Create an outbound carrier
66 |
67 | This assumes you have an upstream carrier that uses username/password to authenticate your calls.
68 |
69 | ```bash
70 | # Create a "resource" representing the carrier
71 | # "rules" is a list of regexes to match numbers for this carrier
72 | # "gateways" is a list of JSON objects representing the gateway(s) to use
73 | curl -X PUT -H "X-Auth-Token: $AUTH_TOKEN" \
74 | -d '{"data":{"rules":[".{5,}"],"name":"Carrier Foo","gateways":[{"realm":"sip.carrier.com","server":"sip.carrier.com","username":"your_username","password":"your_password","enabled":true}]}}' \
75 | http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/resources | python -mjson.tool
76 |
77 | # capture the id of the resource
78 | export RESOURCE_ID="{RESOURCE_ID}"
79 |
80 | # Now create a callflow to use this account resource
81 | # This uses the "no_match" special number
82 | curl -X PUT -H "X-Auth-Token: $AUTH_TOKEN" \
83 | -d '{"data":{"name":"Offnet Callflow","numbers":["no_match"],"flow":{"module":"resources","data":{"use_local_resources":true}}}}' \
84 | http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/callflows | python -mjson.tool
85 | ```
86 |
87 | If you use the regex above, any number 5 digits or more will route to your carrier.
88 |
89 | ## Route numbers to your setup
90 |
91 | Getting numbers to route in Kazoo requires a few steps. This guide will use the defaults in the system (read: mostly US-based numbers) to make this fast. Alternative documentation should be created for handling other areas of the world.
92 |
93 |
94 | ### Add the carrier to the ACLs
95 |
96 | ```bash
97 | sup ecallmgr_maintenance allow_carrier CarrierFoo 1.2.3.4/32
98 | ```
99 |
100 | You can set the IP as a raw IPv4 IP address or in [CIDR notation](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation).
101 |
102 | ### Add a number that you expect your carrier to route to you
103 |
104 | ```bash
105 | curl -X PUT -H "X-Auth-Token: $AUTH_TOKEN" \
106 | -d '{"data":{}}' \
107 | "http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/phone_numbers/+15551234567" | python -mjson.tool
108 |
109 | # Activate the number
110 | curl -v -X PUT -H "X-Auth-Token: $AUTH_TOKEN" \
111 | -d '{"data":{}}' \
112 | "http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/phone_numbers/+15551234567/activate" | python -mjson.tool
113 | ```
114 |
115 | ### Create a callflow for that DID
116 |
117 | You could also amend the callflow created for the first device, adding the number to its "numbers" array.
118 | ```bash
119 | curl -X PUT -H "X-Auth-Token: $AUTH_TOKEN" \
120 | -d "{\"data\":{\"name\":\"Main Callflow\",\"numbers\":[\"+15551234567\"],\"flow\":{\"module\":\"device\",\"data\":{\"id\":\"$DEVICE_ID\"}}}}" \
121 | http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/callflows | python -mjson.tool
122 | ```
123 |
124 | ## Create a PBX
125 |
126 | If you have existing PBXes and want to provide them with SIP trunks, create a "connectivity" doc. Be sure any DIDs you add here have been added in the above method (or similar).
127 |
128 | ```bash
129 | curl -X PUT -H "X-Auth-Token: $AUTH_TOKEN" \
130 | -d '{"data":{"account":{"auth_realm":"{ACCOUNT_SIP_REALM}"},"servers":[{"DIDs":{"+12125554321":{}},"options":{"inbound_format":"e164"},"auth":{"auth_method":"password","auth_user":"{USERNAME}","auth_password":"{PASSWORD}"}}]}}'
131 | http://ip.add.re.ss:8000/v2/accounts/$ACCOUNT_ID/connectivity
132 | ```
133 |
--------------------------------------------------------------------------------
/doc/install/downloading.md:
--------------------------------------------------------------------------------
1 | ## Downloading
2 |
--------------------------------------------------------------------------------
/doc/install/downloading_packages_securely.md:
--------------------------------------------------------------------------------
1 | # Downloading Packages Securely
2 |
3 | By default, `curl` verifies the certificate used on https://packages.2600hz.com. Unfortunately, most installs don't have the particular certificate chain used here. This requires you to download the packages insecurely.
4 |
5 | If you would like to download the packages without having to pass `-k` or `--insecure` to `curl`, follow these steps:
6 |
7 | Download the "Go Daddy Secure Certificate Authority - G2" chain
8 | ```
9 | $ curl --output /etc/pki/tls/certs/gdig2.crt https://certificates.godaddy.com/repository/gdig2.crt
10 | ```
11 |
12 | Add the certificate to nssdb
13 | ```
14 | # certutil -d sql:/etc/pki/nssdb -A -t "C,C,C" \
15 | -n "Go Daddy Secure Certificate Authority - G2" \
16 | -i /etc/pki/tls/certs/gdig2.crt
17 | ```
18 |
19 | This information was obtained from [this post](https://blog.hqcodeshop.fi/archives/304-Fixing-curl-with-Go-Daddy-Secure-Certificate-Authority-G2-CA-root.html).
20 |
--------------------------------------------------------------------------------
/doc/install/install_overview.md:
--------------------------------------------------------------------------------
1 | ## Installation Overview
2 |
--------------------------------------------------------------------------------
/doc/install/install_via_cluster_manager.md:
--------------------------------------------------------------------------------
1 | ## Installing via Cluster Manager
2 |
--------------------------------------------------------------------------------
/doc/install/install_via_debian.md:
--------------------------------------------------------------------------------
1 | ## Installing via DEB
2 |
--------------------------------------------------------------------------------
/doc/install/install_via_iso.md:
--------------------------------------------------------------------------------
1 | ## Install via ISO
2 |
3 |
4 |
5 | **Overview**
6 |
7 | *DISCLAIMER: The Kazoo Single Server ISO is still under development and is not guaranteed to work.*
8 |
9 | If you need a small development or testing **Kazoo** environment, a single server installation may work for you. Keep in mind that only using a single server to host the various **Kazoo** platform software results in limited performance and no redundancy or backups. The **Kazoo** platform was designed to be a scalable, failure resistant platform.
10 |
11 |
12 | ## Installing the ISO
13 |
14 | Prepare your virtual machine or server for installation via ISO. Note that this ISO will overwrite any data on the selected partition/hard drive, so using a virtual machine is preferred. Alternatively, please setup your partitions accordingly. Download the **Kazoo** Single Server ISO here: http://repo.2600hz.com/ISOs/. Make sure to download the latest version. Install the ISO as you would any other **Linux** distribution. The **Kazoo** Single Server ISO is built on **CentOS 6.5**. Remember the root password you set! Once completed, reboot the server and login as the root user.
15 |
16 | When you log in, you will be presented with information regarding your **Kazoo** installation, including the URL for your **Kazoo** web interface and login credentials. By default, this installation method will use a DHCP provided IP. If you are using a static IP, see "Changing IP Settings" below. If you want to change the hostname, you should also do that now. Login to the web interface with the information provided. Please make sure to reset your password! In case you missed it on the previous step, the web interface's URL should look like: (http:///kazoo-ui). You can now start testing your **Kazoo** installation! If you encounter any problems, you can utilize the **Kazoo** **Google Groups: 2600hz-users** and **2600hz-dev**, or visit our public **IRC** channel: **#2600hz** on **Freenode*.
17 |
18 |
19 | ## Using Kazoo
20 |
21 | Were you able to login to the web interface? If so, you have properly installed the Kazoo platform!
22 |
23 | **Changing IP Settings**
24 | By default, this installation method will use a DHCP provided IP. If you as OK with this, then you are set! But if you want to use a static IP, do the following:
25 |
26 | 1. Change your network settings to set your static IP. Run the script `/root/kazoo_ip_set.sh`
27 |
28 | 2. Select STATIC, then select the network interface where your static IP is set. The script will automatically change your Kazoo settings to match your statically set IP. Do you want to use DHCP, but want Kazoo bound on a different network interface? Run the script `/root/kazoo_ip_set.sh`
29 |
30 | 3. Select DHCP, then select the network interface you want Kazoo bound to. The script will automatically change your **Kazoo** settings to bind to the network interface you chose.
31 |
32 |
33 | ## Changing Hostname
34 |
35 | Want to change your hostname? Note that **BigCouch** uses the hostname as a location pointer to where it stores data. For this reason, you will have to wipe out all data in the **Bigcouch** database when you change hostnames. You should probably change hostnames as soon as possible! (It is possible to change hostnames while saving data, but this is out of scope of this simple ISO guide.) Run the script `/root/kazoo_hostname_set.sh`. Follow the script's instructions. Make sure your hostname is fully qualified, this is a requirement for the **Kazoo** platform. The script will change your hostname and update **Kazoo** settings to match.
36 |
37 |
38 | ## Advanced
39 |
40 | By default, this **Kazoo** installation will only be able to utilize local extensions and calling between them. If you want to be able to use real phone numbers and making/receiving calls to/from the outside world, you will need to add your carrier(s) information to the database.
41 |
42 | Note: To access the **BigCouch** database user interface, visit (http://:5984/_utils). For security purposes, this port is blocked by default, so you will either need to forward that port, or temporarily disable iptables.
43 |
44 |
--------------------------------------------------------------------------------
/doc/install/minimum_requirements.md:
--------------------------------------------------------------------------------
1 | # Minimum Requirements
2 |
3 |
4 |
5 | ## Minimal Computational Resources
6 |
7 |
8 | **Kazoo** is designed to be as flexible as possible on what platforms it runs on. Realistically, you would not want to rely on an embedded device with 256MB of RAM to handle 1,000,000 calls per second. That said, with modest hardware **Kazoo** will run just fine for small to medium sized businesses, and scaling to larger capacity servers is relatively seamless and painless.
9 |
10 |
11 | ## Virtualized or not?
12 |
13 | Setting up a **Rackspace**, **Amazon**, **Synapse Global**, or other hosted provider is more than acceptable, especially when starting out. As demands increase, moving the **FreeSWITCH** components onto dedicated hardware (or adding more virtualized nodes) is generally enough to increase performance and capacity. Whether you use a virtualized service, dedicated hardware in a datacenter, or a server on your intranet, **Kazoo** will install and work. You can also setup hybrid clusters where some clients are hosted in your "cloud" while others are hosted on site (replicating and failing over to the "cloud" if the premise server goes down). Since joining a **Kazoo** cluster is easy, the configurations possible are flexible and powerful.
14 |
15 |
16 | ## Operating System Recommendations
17 |
18 | It is strongly recommended that **Kazoo** be deployed on the **Linux** distribution **CentOS**, version 6.4 or 6.5. Since **FreeSWITCH** is a large influence on **Kazoo**, and they recommend using **CentOS**; we have a similar recommendation. Also note that this is the OS of choice for **2600hz**'s production deployments. As time goes on, we will be testing other platforms with **Kazoo** and updating this page with recommendations. However, any operating system that **Erlang** or **FreeSWITCH** run on should suffice.
19 |
20 |
21 | ## Preparing Computational and Operating System Resources
22 |
23 | A fully qualified domain name is REQUIRED
24 |
25 | **Kazoo** relies heavily on your server hostnames being fully qualified domain names (or FQDN). Servers are usually given a short-name, such as "bob", by admins to make it easier to refer to and manage. Fully qualified domain names are comprised of the servers name as well as the domain to which it belongs, such as "bob.example.com". Your system may not be configured to use the FQDN if you did not expressly do so. To find out if your system is properly configured try running the following command:
26 | ```
27 | [root@bob ~]$ hostname -f
28 | bob.example.com
29 | ```
30 | If running running the command above results in both the servers name and the domain it belongs to (basically "bob.something") skip to the next section.
31 |
32 | To configure your system with a FQDN Hostname you can follow these steps:
33 |
34 | We will modify the systems "hosts" file such that it will be able to understand a FQDN (such as "bob.example.com") belongs to an IP address. The hosts file can be found at `/etc/hosts`.
35 |
36 | If you have a DNS server for the domain, say "example.com" rather than modify the hosts file you could add an A record "bob.example.com" with the servers IP. This will make it easier to manage the cluster if the IP addresses of the equipment is expect to change. However, if you use a DNS service (rather than the hosts file) to resolve the FQDN of the servers in your cluster you need to ensure it is 100% available! DNS failure in this configuration will disrupt voice service.
37 |
38 |
--------------------------------------------------------------------------------
/doc/install/planning_zones.md:
--------------------------------------------------------------------------------
1 | ## Planning out zones
2 |
3 |
--------------------------------------------------------------------------------
/doc/intro/advanced-concepts.md:
--------------------------------------------------------------------------------
1 | ## Kazoo Dedicated Cluster Guide
2 |
3 |
4 |
5 | **This is our core open-source product and the basis for our company. Everything listed here is effectively open-sourced:**
6 |
7 | 1. Cluster Deployment
8 |
9 | 2. Configuration
10 |
11 | 3. Maintenance
12 |
13 | 4. Troubleshooting
14 |
15 |
--------------------------------------------------------------------------------
/doc/intro/build-own.md:
--------------------------------------------------------------------------------
1 | ## Build Your Own Cloud Platform
2 |
3 |
4 |
5 | This section covers how to build your own cloud platform on your own hardware or infrastructure.
6 |
7 |
--------------------------------------------------------------------------------
/doc/intro/build_system.md:
--------------------------------------------------------------------------------
1 | ## Build System
2 |
3 |
4 |
5 | We may be revising the build system to meet the demands of additional use cases. This document is a work-in-progress. As the project has grown, more use-cases have evolved. Here are some we've learned about:
6 |
7 | 1. Desire to install on **Debian**, **CentOS**, **FreeBSD**, **Windows**
8 | 2. Desire to install on networks and servers which are 100% secure and private WAN
9 | 3. Desire to host all packages in a separate, non-public repository
10 | 4. Desire to have all dependencies packaged on a single CD or installation disk
11 | 5. Desire to be able to provide single-server upgrade procedures and installation media for remote sites
12 |
13 |
14 | ## Customer Use Cases Include:
15 |
16 | 1. Internet Telephony Service Providers
17 | 2. Fire, Police and Military and Secure Installations With Disparate Sites
18 | 3. Health Care Industries with HIPAA compliance concerns
19 | 4. Installations who intend to be 100% self-sufficient and run everything on a private WAN for security
20 | 5. Installations where the logic and database servers are on non-public IPs and do not allow public internet access
21 |
22 |
23 | ## Current Strategy:
24 |
25 | Bundle everything in the RPM, including all libraries, wherever possible
26 |
27 |
28 | ## Current Problems:
29 |
30 | 1. Effectively forking dependencies. Changes in our repo/dependencies can not be preserved when the dependency is upgraded
31 | 2. Individuals using/working with the project may end up testing/working on old dependency libraries. Upgrades to those libraries may break their work
32 | 3. The current source deployment model proposes a git clone into /opt/kazoo, which results in locally modified config files (`whistle_apps/conf/vm.args` and such) being shown in "**git status**", and they can accidentally be added to the repository.
33 |
34 |
35 | ## New Proposed Standards:
36 |
37 | 1. **Git** repository should only contain sources, and no derivatives (such as beams). This applies to all sources, including third-party dependencies.
38 | 2. The build process should generate all needed beams and other derivatives
39 | 3. The source code does not assume any directory paths, and all the installation paths are defined during the installation (currently, for example: `utils/sup/src/sup.erl` contains "`/opt/kazoo`" hardcoded)
40 | 4. Desirable: strict separation of source directory, installation directory, and configuration directory. This is difficult to achieve within rebar paradigm, as it does not offer installing the application into a target path.
41 | 5. Installed scripts contains direct links to external binaries, such as full path to the Erlang interpreter. This will allow multiple Erlang versions exist on the same server (currently: "erl" from current PATH is used).
42 |
43 |
44 | ## New Proposed Methods:
45 |
46 | 1. GNU Autoconf/Automake – seems to be a quite hardcore task to combine with rebar. One big difference is that automake assumes the source and target paths to be different, while rebar assumes that the source and installation paths are the same.
47 |
48 | 2. Shell scripts for configuration and installation:
49 |
50 | a. Configuration script: takes the installation path (which is equal to CWD), **Erlang** path, configurable options such as cookies and hostnames, and generates the configuration files. These config files are never a part of **Git** repository. The configuration script is executed only once, and aborts if the configuration files already exist. Further modifications are done on configuration files directly. It is desirable to keep the config files outside of Kazoo installation path, then they can be added into their own git repository.
51 |
52 | b. Build script generates all beams and other required derivatives. If any of source files are updated, the corresponding beams are re-built. The build script never modifies configuration files from #1.
53 |
54 | c. Test script validates the current installation
55 |
56 | ## Unresolved architecture issues:
57 |
58 | Do we need to move all third-party dependencies outside of **Kazoo** repository?
59 |
60 | **Pros:**
61 |
62 | Easier to test new versions of third-party libraries.
63 | All original change history in third-party libraries is preserved.
64 | Possibility to use pre-packaged third-party libraries.
65 | A major update in a third-party library does not pollute kazoo repository.
66 |
67 | **Cons:**
68 |
69 | Need to maintain reliable repositories for all dependencies.
70 | More complexity in installation scripts.
71 | Need a script which fetches all third-party dependencies for offline installation.
72 |
73 |
--------------------------------------------------------------------------------
/doc/intro/cluster-design.md:
--------------------------------------------------------------------------------
1 | ## Single Server
2 |
3 |
4 |
5 | **Active / Active Cluster Design**
6 |
7 | **Active / Passive Cluster Design**
8 |
9 | **Multi-Zone Design Considerations**
10 |
11 |
--------------------------------------------------------------------------------
/doc/intro/component_overview/intro.md:
--------------------------------------------------------------------------------
1 |
2 | ######**OpenSIPS**
3 |
4 | **OpenSIPS** acts as a load balancer for the SIP requests (much the way nginx or HAProxy are used to load balance web requests). We minimize the number of public network interfaces needed to inform clients and carriers of by pointing them to the load balancers (usually two for redundancy). Adding capacity becomes as easy as informing openSIPS of the new switch.
5 |
6 | to the Switch...
7 |
8 |
9 | ######**FreeSWITCH**
10 |
11 | We primarily use **FreeSWITCH** in this layer because of the tight integration we get between **Kazoo** and **FreeSWITCH** via the
12 | `mod_erlang_event` module. As **FreeSWITCH** is already a carrier-grade switch on its own, bringing the clustering features of **Kazoo** on top, you get a truly high-quality cluster of switches on which to build your business.
13 |
14 | to the Control Layer...
15 |
16 |
17 | ######**Control Layer - Kazoo**
18 |
19 | **Kazoo** provides an abstraction layer (among other things) to the underlying switching layer. Application developers can program their applications against the **Kazoo** APIs and know that Kazoo will take care of the details. Application developers also benefit from Kazoo's ability to distribute processing amongst the servers in the switching layer. To the application developer, Kazoo is one logical switch.
20 |
21 | to the Message Bus...
22 |
23 |
24 | ######**RabbitMQ**
25 |
26 | We primarily start and conduct conversations between servers using a standard protocol named AMQP, which is implemented via a program named **RabbitMQ**. While we've had discussions about
27 | faster systems like **ZeroMQ** (theoretically anyway), **RabbitMQ** allows us to keep everything in native Erlang data types, pass things around our software quickly, and cluster **Kazoo** and **WhApp** servers easily. It also implements all the brokers we need out-of-the-box.
28 |
29 | to the Logic...
30 |
31 |
32 | ######**WhApps**
33 |
34 | **WhApps** can control what happens at all stages of a call (even initiate calls of their own). Authentication, routing, in-call applications (like IVRs and voicemail), and more, are all exposed via the **Kazoo** APIs. We provide a set of APIs via a REST interface, implemented as a **WhApp** named **Crossbar**. With **Crossbar**, configuration of PBX functionality and more is exposed. Other **WhApps** included are Registrar (authentication and distributed registration server), **Callflow** (real-time dialplan execution), **MediaMgr** (real-time streaming of MP3 and WAV media files to the switching layer), and **Trunkstore** (trunking platform).
35 |
36 | to the Storage....
37 |
38 |
39 | ######**BigCouch**
40 |
41 | Its a known secret that **BigCouch** is the magic fairy dust that makes **Kazoo** so reliable. With the ability to replicate data, dynamically adjust the read and write quorums, and a simple-to-use HTTP interface, developing our platform using **BigCouch** as the long term datastore has been a huge win. As important, from an operational perspective, once you understand the knobs and levers to turn to tweak the performance characteristics, **BigCouch** is a breeze to operate and maintain.
42 |
--------------------------------------------------------------------------------
/doc/intro/contributing.md:
--------------------------------------------------------------------------------
1 | ## Contributing
2 |
3 |
4 |
5 | ## Code
6 |
7 | xxx
8 |
9 | ## Documentation
10 |
11 | xxx
12 |
13 | ## Reward System
14 |
15 | xxx
16 |
--------------------------------------------------------------------------------
/doc/intro/create-template.md:
--------------------------------------------------------------------------------
1 | ## Create A Template
2 |
3 |
4 |
5 | Give your authors a helping hand by using templates in your documentation space. You will need "Space Administrator" permissions to create templates.
6 |
7 | To create a Template:
8 |
9 | 1. Go to 'Space Tools' in the sidebar, select 'Content Tools' and create a new template.
10 |
11 | 2. Click 'Page Layout' and add sections and columns to your page. Add headings and sub-headings as needed.
12 |
13 | 3. Choose 'Instructional Text' from the 'Template' menu and add text that is only visible in the editor. Save your template.
14 |
15 | 4. Your template will become available in the 'Create' dialog for this space.
16 |
17 |
18 | *Useful hint: **Confluence** Administrators can also make templates that are available across your whole **Confluence** instance.
19 |
--------------------------------------------------------------------------------
/doc/intro/disabling-servers.md:
--------------------------------------------------------------------------------
1 | ## Disable Servers
2 |
3 |
4 |
5 | Preparing servers for an upgrade requires gracefully disabling them without dropping any calls.
6 |
7 |
--------------------------------------------------------------------------------
/doc/intro/distributed-reg.md:
--------------------------------------------------------------------------------
1 | ## Traditional Registration
2 |
3 |
4 |
5 | When a business or hobby first starts out, a single switch is the typical starting point. Clients point their devices to the IP of the switch, registration credentials are stored on the switch, and life is good. Then the switch begins to fill up with clients, to the point where a second server is needed handle the capacity demands. No problem; new clients on the new switch. But what happens when a client on the first switch grows? Migrate them to the new switch? Setup another switch just for them? But now you have to change the configurations on their devices, update carriers that routed DIDs to the first switch, perhaps you customized some features for that client that now have to be migrated as well...in short, it gets unwieldy fast.
6 |
7 | This speaks nothing of the fact that if that server crashes (for a host of reasons, some controllable, some not), all clients on said switch are without service. Even when you have a hot spare or master-master setup, its no guarantee the system will survive a crash. If both servers are at 70% load, when one goes down, that 70% is headed to the other switch. How fast can the ops team spin up a new server?
8 |
9 |
10 | ## A Better Way
11 |
12 | At a general level, the softswitch was not built to handle the distributed case. They route calls, handle codec transcoding (if necessary), but they assume they are the authority on what devices can connect and how to find devices for calls.
13 | **Whistle** has relieved them of that concern (and others). When a registration request is received by the switch, it asks **Whistle** to give it the necessary credentials to verify the device. If successful, the switch lets **Whistle** know; **Whistle** then sends the successful registration information out the any listening WhApps (in our case, `registrar`, which stores them in **BigCouch** for later retrieval).
14 |
15 | Now, when the switch receives a call that needs to be routed to a known device, it just asks **Whistle** for the contact information and sends the SIP traffic on its merry way. The handling switch, however, need not have ever interacted with the device before that point.
16 |
17 |
18 | ## Why Do I Care?
19 |
20 | Because the switch is agnostic to devices, and instead trusts **Whistle** to guide it in routing calls, your clients can register their devices to any of the switches in your cluster, and carriers can send calls destined for your clients to any of the switches as well. Better still, you can put a load balancer in front of your switches, giving your clients two IPs (assume two load balancers for redundancy) to register their devices against. These load balancers keep no history of what device hit which switch last time but distribute the load evenly across your cluster.
21 |
22 | Capacity issues? Add a switch into the cluster behind the load balancers, update the load balancers' configs, and voila, increased capacity without the client or carrier changing a single setting.
23 |
24 |
25 | ## Tangential Benefits
26 |
27 | Because the switch is no longer storing state between calls, performance gains are noticeable as disk activity and memory usage decreases, which increases capacity as more concurrent calls can be loaded on a single switch. Plus, impacts from a switch going down are limited to the current calls (and some switches, namely **FreeSWITCH**, are building functionality to be able to rebuild an in-progress call on a new server). When those calls restart, they are evenly distributed across your remaining cluster, not overwhelming the hapless hot spare or co-master.
28 |
29 | Capacity planning becomes much easier when you can spread load from a single failed switch across 3, 5, 10, or even 100 other switches. As the number of switches increases, your ability to load them with higher and higher sustained call rates without fear of cascading failures grows as well.
30 |
--------------------------------------------------------------------------------
/doc/intro/expand-cluster.md:
--------------------------------------------------------------------------------
1 | ## Expand Cluster
2 |
3 |
4 |
5 | How to safely expand the cluster to a new server, datacenter or continent
6 |
7 |
--------------------------------------------------------------------------------
/doc/intro/g729-licensing.md:
--------------------------------------------------------------------------------
1 | ##G729 Licensing
2 |
3 |
4 |
5 | Installing and managing G729 licenses
6 |
--------------------------------------------------------------------------------
/doc/intro/get_help.md:
--------------------------------------------------------------------------------
1 | ## Get some help!
2 |
--------------------------------------------------------------------------------
/doc/intro/getting-started.md:
--------------------------------------------------------------------------------
1 | ## Getting Started
2 |
3 |
4 |
5 | ## Create a page
6 |
7 | Click 'Create' and select 'Blank' Page to create your first page. New pages are created as children of the page you are currently viewing.
8 |
9 |
10 | ## Add to your page
11 |
12 | Click 'Edit' to enter the **Confluence** editor and use the page layouts feature to structure your content using sections and columns. Use headings to format your text and drag and drop images into your page to provide visual interest. Click 'Insert' and select 'Other
13 | Macros' to add macros for navigation, special formatting and other media:
14 |
15 | 1. Create a page
16 |
17 | 2. Add to your page
18 |
19 | 3. Organise your pages
20 |
21 | 4. Change the page order
22 |
23 | 5. Add labels
24 |
25 | 6. Make templates
26 |
27 |
28 | ## Organise your pages
29 |
30 | Here are some tips for organising your content:
31 |
32 | Change the page order.The sidebar on the left displays your pages in a hierarchy. If you have 'Space Administrator' permissions you can click 'Space Tools' to reorder Pages to move pages around.
33 |
34 |
35 | ## Add labels
36 |
37 | Labels help keep pages organised and make it easier for you to find the information you need. Click 'Labels' at the bottom of a page to
38 | add or edit. The Related pages section on this page uses labels too!
39 |
40 |
41 | ## Make templates
42 |
43 | Standardise and speed up the page creation process with templates. You can create and format a template with page layouts, standard headings and instructional text for hints and guidelines. Check out our sample page on making a template.
44 |
45 |
46 |
--------------------------------------------------------------------------------
/doc/intro/happy-programmer.md:
--------------------------------------------------------------------------------
1 | ## Happy programmers write happy code
2 |
3 |
4 |
5 | Summarized thus:
6 |
7 | *Only program the happy case, what the specification says the task is supposed to do ~ Joe Armstrong*
8 |
9 | Did you know that **Erlang** programmers would make mighty fine actors (or at least actor managers)? Besides the fact that they deal with
10 | actors all day long (**Erlang** processes), they also take on the character of the process. When branching (using case, if, or function clauses), the executing process needs to determine "Do I know how to handle an error here?"
11 |
12 | A common idiom is to return `{ok, Result}` or `{error, Error}` when calling another module to do something for you. If you, the calling process, don't know what to do with `{error, Error}`, why branch? Just match `{ok, Result}` and continue programming the happy case. Let some one else (a supervisor or whomever spawned you) clean up the mess. That said, if you know how to handle the error, you should certainly branch and handle it appropriately. It's not always this cut and dry, of course, but asking, "Do I know how to handle an error here?" is a good start to deciding whether to wrap that function call in a case statement or not. If this is a long-running server, failing intentionally probably isn't a wise course of action. However, if it's a worker process spawned by the server, it's likely okay to not handle the error. By keeping your workers' outlooks happy, you simplify and reduce the amount of code in those workers, and hopefully make it easier to reason about them when determining if they are meeting their specification.
13 |
--------------------------------------------------------------------------------
/doc/intro/inbound-call-issue.md:
--------------------------------------------------------------------------------
1 | ## Inbound Call Issues
2 |
3 |
4 |
5 | When a customer complains an inbound number isn't working:
6 |
7 | 1. Call the number yourself, see if it rings from a system phone.
8 |
9 | 2. Call the number from your cell phone or an out side line. See if it rings. If it works outside but not inside...
10 |
11 | 3. If it works inside but not outside...
12 |
13 | 4. If the above both work:
14 |
15 |
16 |
--------------------------------------------------------------------------------
/doc/intro/kazoo-media.md:
--------------------------------------------------------------------------------
1 | ## Kazoo Media
2 |
3 |
4 |
5 | ## Streaming Audio (mp3 and wav) to FreeSWITCH from Erlang
6 |
7 | One of the biggest challenges to overcome with distributing **FreeSWITCH** servers inside your cluster is getting them access to the same media files, both system and user-generated (like voicemails and custom prompts). Replicating (via rsync or similar) files amongst the **FreeSWITCH** servers works at a small scale, but increase over a few servers and the operational requirements accelerate.
8 |
9 |
10 | ## Challenges
11 |
12 | How to ensure each server has the same set of media files?
13 |
14 | How to ensure each server has the same version of media files?
15 |
16 | How to ensure each server received a copy of a media file?
17 |
18 | How to ensure a newly added server gets all the updated media?
19 |
20 | How to ensure a newly added server gets any new media?
21 |
22 | Will each server realistically be able to store all media across the system?
23 |
24 |
25 | ## To The Cloud Stateless Switch
26 |
27 | If a switch or subset of switches are responsible for storing a client's voicemail files, we have a point of failure with respect to that client. With the single switch setup, it is an obvious point of failure. As you increase the number of switches storing media, the operational costs begin to increase (while the likelihood of losing those files decreases). However, the client is still limited in which switch they are able to hit and retrieve their media.
28 |
29 | A guiding decision we've made in **Whistle** is that the underlying switching servers should be as "dumb" as possible with respect to the decision making process. Included in this decision is the storage of client media. As seen above, the job of synchronizing media across the cluster is difficult in the switching layer. Whistle instead pushes the responsibility of handling media up to the **WhApp** layer. As long as a switch is managed by **Whistle**, and Whistle is connected via messaging bus to a **WhApp** that handles media distribution, all switches have access to the same media.
30 |
31 | The biggest enablers of this strategy, from the switch's perspective, are two **FreeSWITCH** modules: `mod_shout` and `mod_shell_stream`. `mod_shout` provides us with an entry point for both streaming mp3 media into a call, as well as streaming recordings from **FreeSWITCH** to Whistle (more on this later). `mod_shell_stream`, as the wiki states, allows you to "stream audio from an arbitrary shell command". Combining this with a simple cURL+sox script, we now have the building blocks to stream all audio to/from **Whistle/WhApps**.
32 |
33 |
34 | ## Media Manager
35 |
36 | Included with **Whistle** is a media management **WhApp** named `media_mgr`.
37 |
38 |
39 | ## Sending Audio to FreeSWITCH
40 |
41 | When **Whistle** encounters a dialplan action requiring media, it makes a request to the message bus asking for an accessible URL from which to stream the media. `media_mgr` receives the request and does a lookup in the data-store for the requested media. If found, a stream process is created and give the data necessary to stream the chosen media contents. The media type (WAV or MP3) determines the type of stream (HTTP or SHOUT, respectively). The stream process crafts a URL with the port it will be listening on and sends the response back to the **Whistle** process handling the call.
42 |
43 | **Whistle** checks the protocol of the URL received to determine how to send the stream to **FreeSWITCH**. If the protocol is http:// (WAV), Whistle knows that mod_shell_stream should be invoked and creates the play command to do so. If the URL is shout://, **Whistle** passes it along to **FreeSWITCH**; **FreeSWITCH** then passes control to `mod_shout` to pull the actual contents down.
44 | `mod_shell_stream` script. To invoke `mod_shell_stream`, **Whistle** passes a command to **FreeSWITCH** similar to:
45 |
46 | `shell_stream:///path/to/fetch_remote_audio.sh http://mediamgr.url.com/stream.wav`
47 |
48 | The `fetch_remove_audio.sh` script makes an HTTP request to the stream URL, and pipes the body (the WAV contents) to sox, which in turn sends the data into **FreeSWITCH**.
49 |
50 |
51 | ## Recording Audio
52 |
53 | `mod_shout` also allows us to stream a recording to a SHOUT server rather than to the local disk, critical when a voicemail is being left.
54 | Our voicemail is actually a callflow module and sends a MediaName to **Whistle** to identify the recording for later use in the call. **Whistle**, when executing the record instruction, creates a SHOUT server process and sends the URL along with the record command, something along the lines of:
55 |
56 | `shout://foo:bar@whistle.server.com:39266/fs_02688d5d2b37267a2e9496d156cb52dd.mp3 120 500 5`
57 |
58 | Yes, the `foo:bar` is actually used. `mod_shout` uses basic HTTP auth to connect to the **Whistle** SHOUT server, expects an appropriate response, and then streams the recording to **Whistle**. **Whistle** stores this recording to its local disk. If the user on the call wants to review the recording, **Whistle** actually sets up a SHOUT streaming server, much like `media_mgr` did, and streams the recording back into **FreeSWITCH**. When the **WhApp** controlling the call issues a store command, in this case passing the **CouchDB** URL with attachment to stream into, Whistle reads the file off its local disk and streams away as normal. Once the phone call ends, the recorded media will be streamed via `media_mgr` (say when a user checks their voicemail).
59 |
--------------------------------------------------------------------------------
/doc/intro/load-failure.md:
--------------------------------------------------------------------------------
1 | ## Load Failure
2 |
3 |
4 |
5 | Border systems down
6 |
7 | Database issues
8 |
9 | Timeouts in Erlang Event
10 |
11 | FreeSWITCH stability
12 |
13 | Flapping
14 |
15 | Jitter
16 |
17 | Data corruption
18 |
19 | Data growth
20 |
21 | When to spin up new systems
22 |
--------------------------------------------------------------------------------
/doc/intro/milliwatt.md:
--------------------------------------------------------------------------------
1 | ## Milliwatt
2 |
3 |
4 |
5 | Milliwat allows automatic echo testing and tone stream.
6 |
--------------------------------------------------------------------------------
/doc/intro/number-lifecycle.md:
--------------------------------------------------------------------------------
1 | ## Number Lifecycle
2 |
3 |
4 |
5 | This document describes the lifecycle of direct inward dialing (DID) numbers.
6 |
7 |
8 | ## Figure Discovery
9 |
10 | 1. This is an internal number state used to temporarily hold information regarding numbers users can acquire from the system owner carriers.
11 |
12 | 2. Populated (usually) by API requests to the carriers.
13 |
14 | 3. Does not participate in number hunts.
15 |
16 | 4. No accounts have authority to transition to/from this state.
17 |
18 | 5. There are no public fields for discovery numbers.
19 |
20 | 6. Any account can transition an available number to reserved.
21 |
22 |
23 | ## Port In
24 |
25 | 1. This is a temporary state for a newly added number by an account via the porting API.
26 |
27 | 2. Automatically transitions to `in_service` the first time hunted by the system (first call to it). Does not participate in the off-net number hunt, meaning it is only used to route inbound and will not keep calls on-net. No accounts have authority to transition to/from this state.
28 |
29 | 3. Any account can create a `port_in` number if it does not exist in the system.
30 |
31 | 4. The public fields of a `port_in`number can be managed by the assigned account or an ancestor of the assigned account.
32 |
33 | 5. Only numbers in the `port_in` state allow the porting documents to be managed.
34 |
35 | 6. These numbers can only exist in the following states: `in_service`, `port_out`, and `disconnected`.
36 |
37 | 7. None of these transitions can be preformed by accounts.
38 |
39 |
40 | ## Available
41 |
42 | 1. This is a number that has been routed to the cluster but has no account assignment. Any account can transition these numbers to `reserved` or `in_service` if they wish to obtain control of it.
43 |
44 | 2. Does not participate in number hunts. Any account can transition an `available` number to `reserved`.
45 |
46 | 3. Any account can transition an `available` number to `in_service` if it is not of type `knm_local`.
47 |
48 | 4. There are no public fields for available numbers, but they can be created during a transition.
49 |
50 |
51 | ## Reserved
52 |
53 | 1. This is a number that an account has acquired for themselves or their children.
54 |
55 | 2. Some accounts can create reserved numbers.
56 |
57 | 3. Does not participate in number hunts.
58 |
59 | 4. Numbers coming from the discovery state will be acquired via the carrier modules.
60 |
61 | 5. An account can transition a reserved number to `in_service` if one of the following criteria is met:
62 |
63 | a. The requesting account is the same as the assigned account.
64 |
65 | b. The requesting account is an ancestor of the assigned account.
66 |
67 | c. The requesting account is an descendant of the assigned account.
68 |
69 | d. The new account assignment is the same or a descendant of the current assignment.
70 |
71 |
72 | 6. An account can reserve a 'reserved number' if one of the following criteria is met:
73 |
74 | a. The requesting account is an ancestor of the assigned account.
75 |
76 | b. The requesting account is an descendant of the assigned account.
77 |
78 | c. The new account assignment is a descendant of the current assignment.
79 |
80 | d. When a number is reserved the new assignment is added to the history of assignments.
81 |
82 | 7. A flagged account can create a reserved number of type `knm_local`. These numbers can only be acquired and managed by the creating account or a descendant.
83 |
84 | 8. E911 assignments will be maintained, if present.
85 |
86 | 9. The public fields of a reserved number can be managed by the assigned account or an ancestor of the assigned account.
87 |
88 |
89 | ## In Service
90 |
91 | This is a number that belongs to an account.
92 |
93 | *Participates in number hunts.*
94 |
95 | An `in_service` number can be transitioned to `reserved` if the requesting account is, or an ancestor of, the assigned account for the number.
96 |
97 | E911 assignments will be maintained, if present.
98 |
99 | The public fields of an `in_service` number can be managed by the assigned account or an ancestor of the assigned account.
100 |
101 |
102 | ## Released
103 |
104 | This is an aging state that numbers added to the system via discovery remain for a period of time till moving back to available to start the cycle again.
105 |
106 | *Does not participate in number hunts.*
107 |
108 | If a `reserved` number is released:
109 |
110 | With an assignment history it remains `reserved` but is re-assigned to the previously assigned account.
111 |
112 | Without an assignment history and is of type `knm_local` it transitions to disconnected.
113 |
114 | Any other type completes the transition to released.
115 |
116 | If an `in_service` number is released:
117 |
118 | With an assignment history it becomes `reserved`and is re-assigned to the previously assigned account
119 |
120 | Without an assignment history and is of type `knm_local` it transitions to `disconnected`
121 |
122 | Any other type completes the transition to `released`
123 |
124 | The public fields of an released number are removed.
125 |
126 | Released numbers can be transitioned to available by the system or system admin accounts only.
127 |
128 | E911 is disconnected, if present.
129 |
130 |
131 | ## Port Out
132 |
133 | This is an administrative step to releasing numbers. It operates like 'Port In' except that inbound requests do not move it to In Service.
134 |
135 |
136 | ## Disconnected
137 | This is an internal number state, and marks the number for a permanent move from the active datastore to the archive.
138 |
139 |
--------------------------------------------------------------------------------
/doc/intro/read_me_first.md:
--------------------------------------------------------------------------------
1 | ## READ ME FIRST
2 |
3 |
4 |
5 | **Kazoo** is a sophisticated piece of software that allows for large-scale clustering across a WAN. While it is intended to be simple, at times, it can have a high learning curve.
6 |
7 |
8 | ## Required Skills
9 |
10 | You should seriously consider whether you're ready to undertake deploying and managing the entire infrastructure from the start. We now recommend starting with our hosted platform. You can always move to your own software and equipment at any time, without losing data or incurring downtime.
11 |
12 | There are two main areas you are going to need to learn when you dive into **Kazoo**:
13 | 1. How to Setup Customers
14 | * via the GUIs
15 | * via the APIs
16 | 2. How to Manage the Back-end
17 | * FreeSWITCH
18 | * BigCouch
19 | * Kamailio
20 | * Kazoo
21 | * eCallMgr
22 | * RabbitMQ
23 | 3. Client DNS Mapping
24 |
25 | The **Kazoo UI** & APIs may take you a few weeks to become familiar with. The back-end will probably take a bit longer.
26 |
27 | We've structured things so you can start out on our hosted platform. It's inexpensive and it lets you get to know the system prior to diving into the deep end and trying to run it all yourself. There's enough to learn in the system as-is! You can customize the entire experience for your customers while using our hardened hosted system and you can move your customers seamlessly when you are ready to manage your own infrastructure.
28 |
29 |
30 | ## Required Knowledge and Facilities
31 |
32 | **Consider Hosting With Us**
33 |
34 | If you're truly ready to dive into running your own cluster, please be sure you understand what's involved. You must:
35 |
36 | Have a highly reliable datacenter with extremely consistent network connectivity. Too many people make the mistake of assuming - "I've used them for web hosting for years" - this isn't web hosting! Phone calls require uninterrupted connectivity.
37 |
38 | Have a good understanding of **Linux**, including debugging firewall and network connectivity
39 |
40 | Have some understanding of databases and database clusters
41 |
42 | Helpful to have at least played with **BigCouch**, **Erlang**, **FreeSWITCH** and/or **Kamailio** a little
43 |
44 | If you can genuinely meet all the requirements above, the sky is the limit on what you can build! Enjoy.
45 |
46 |
--------------------------------------------------------------------------------
/doc/intro/resources.md:
--------------------------------------------------------------------------------
1 | Resources
2 |
3 | Packages
4 |
5 | GitSwitch
6 |
7 | Jenkins/Hudson?
8 |
9 | CI
10 |
11 | Travis
12 |
13 |
--------------------------------------------------------------------------------
/doc/intro/startup-sequence.md:
--------------------------------------------------------------------------------
1 | Understanding the startup sequence can be essential in debugging.
2 |
3 |
--------------------------------------------------------------------------------
/doc/intro/storefwd.md:
--------------------------------------------------------------------------------
1 | ## Store and Forward (T.37)
2 |
3 |
4 |
5 | ##Ways to transmit a Fax over IP:
6 |
7 |
8 | ## PCMU
9 |
10 | Plain old audio, uncompressed (64k) regular phone line. PCMU is OK if you can guarantee the audio signal is consistent around 200-300ms latency. T.38 - At least two sides must understand T.38 to use it:
11 |
12 | Negotiation was be successful between the two sides. Who negotiates first?
13 |
14 | v0, v1, v2, v3, ECM, v17 - Max Speed (14400/9600)
15 |
16 | Redundancy Feature - FAX - ATA - CLOUD - v1, v2, v3
17 |
18 |
19 | ## STEPS FOR T.38 TO WORK:
20 |
21 | Two devices must be able to hear each other initially via voice (to detect the tones)
22 | Best way to test: CALL THE FAX MACHINE. Also, have them call you from the fax machine if possible. CLUE: No t38 message in the logs AND hang up within 15-30 seconds. CATCH: Many fax machines don't answer for 5 rings, and your calling timeout might be too long. You'll see NO_ANSWER in the FreeSWITCH log. Two devices must be able to negotiate T38 either with each other or with the upstream phone company (You won't know who's on the other side, and that's OK). You will see a log entry in the FS log that a negotiation of T38 was attempted. You will then see a reply from the other side of either Not Acceptable Here / Incompatible Destination OR OK. In addition, the OK will come back with the confirmed parameters
23 |
24 |
25 | ## For Testing:
26 |
27 | 1. Need One (1) Physical Fax that can Send/Receive
28 | 2. Need One Virtual or Physical Fax that can Send /Receive
29 | 3. PATIENCE!
30 | 4. Test PCMU. Should work over fast connection but may not always - The most optimized services should work, so for example RingCentral
31 | Our Fax to Email (server) Service. Probably won't work to a real fax machine
32 | 5. Test Two-way Audio
33 | 6. Test Long/Complex Faxes
34 | 7. Test Short/Simple Faxes
35 | 8. Test Two Model ATAs :-) and no more then two models.
36 | 9. Test Two Fax Machines.
37 | 10. Test error conditions and how OUR software handles them.
38 | 11. Inspect quality for lost rows/lines.
39 | 12. Someday test store forward.
40 | 13. Test Failback abilities on our side.
41 |
42 |
--------------------------------------------------------------------------------
/doc/kazoo/call-rating.md:
--------------------------------------------------------------------------------
1 | ## CALL RATING
2 |
3 |
4 |
5 | **Kazoo** provides a basic facility to load a rate-deck into the system for the purpose of rating each call. The rate is only utilized if
6 | the system determines the caller does not have any flat-rate services available for the number being dialed.
7 |
8 | 1. How to load the rate deck
9 |
10 | 2. How to test the rate deck (if possible)
11 |
12 | 3. How to check our costs vs. retail costs
13 |
14 | 4. How to make sure the rating module is loaded / running / being utilized
15 |
16 | 5. Info dump to later be cleaned up
17 |
18 |
19 | **Call Rating** is handled by the **HotOrNot** application. When it starts up for the first time, it will create a database called "Ratedeck" and load an initial rate document for US-domestic calls. That document looks like:
20 |
21 | ```
22 | { _id : US-1, direction: [ inbound, outbound ],
23 | pvt_internal_rate_cost : 0.01,
24 | iso_country_code: US, options: [ ],
25 | prefix: 1,
26 | rate_cost: 0.02,
27 | rate_increment: 60,
28 | rate_minimum: 60,
29 | rate_name: US-1,
30 | rate_surcharge: 0.00,
31 | routes: [^0111(\\d{10})$, ^\\+1(\\d{10})$],
32 | pvt_type: rate
33 |
34 | }
35 | ```
36 |
37 | ## Create your own rate document
38 |
39 | `_id` is arbitrary, but we recommend using `iso_country_code` + prefix direction determines whether to apply the rate to an inbound or
40 | outbound call (or both).
41 |
42 | `pvt_internal_rate_cost` // is what you are charged by your upstream carrier (optional)
43 |
44 | `iso_country_code` // what country this rate is applicable.
45 |
46 | `options` // what features does this rate apply to. You might put `[Fax]` for a rate, and if a fax machine is configured and has the same
47 | flag in its settings, this rate will be used.
48 |
49 | `rate_cost` // how much the call will cost, per rate_increment
50 |
51 | `rate_increment` // how many seconds the `rate_cost` applies to. So $0.02 for `rate_cost` and 60 for `rate_increment` means 2 cents per minute.
52 |
53 | `rate_minimum` // how many seconds to bill for at a minimum. If a call lasts 30 seconds and `rate_minimum` is 60, bill it as a 60-second
54 | call.
55 |
56 | `rate_name` // friendly name, eventually will be exposed in the GUI
57 |
58 | `rate_surcharge` // flat rate to charge for connecting the call.
59 |
60 | `routes` // list of regex to apply to the dialed DID to determine if this rate is eligible to be applied to the call.
61 |
62 | `pvt_type` //
63 |
64 | `rate` //
65 |
66 |
67 | ## Other info
68 |
69 | The rate chosen is based on the prefix length. So if I have two rates with routes that match the dialed DID, one with prefix '1' and one with prefix '123', the rate for prefix '123' will be applied. The rate information is placed in the channel variables and will appear in the call's **CDR** data under the `Custom-Channel-Vars` field.
70 |
--------------------------------------------------------------------------------
/doc/kazoo/ecallmgr-cmd.md:
--------------------------------------------------------------------------------
1 | ## Kazoo ECallMgr
2 |
3 |
4 |
5 | Also, you are the only person receiving `low_balance` (code change). I have also stopped the `jonny5` reconciler:
6 |
7 | `sup jonny5_maintenance stop_reconciler`
8 |
9 |
10 | ## The following functions are now available for conferences:
11 |
12 | ```
13 | sup -necallmgr ecallmgr_maintenance conference_summary
14 |
15 | sup -necallmgr ecallmgr_maintenance conference_details
16 | ```
17 |
18 |
19 | ## To fix any errors there is also:
20 | ```
21 | sup -necallmgr ecallmgr_maintenance sync_conferences
22 |
23 | sup -necallmgr ecallmgr_maintenance sync_conferences freeswitch@server.com
24 |
25 | ```
26 | ## This brings the complete list to:
27 | ```
28 | sup -necallmgr ecallmgr_maintenance add_fs_node freeswitch@server.com
29 |
30 | sup -necallmgr ecallmgr_maintenance remove_fs_node freeswitch@server.com
31 |
32 | sup -necallmgr ecallmgr_maintenance node_summary
33 |
34 | sup -necallmgr ecallmgr_maintenance node_details
35 |
36 | sup -necallmgr ecallmgr_maintenance node_details freeswitch@server.com
37 |
38 | sup -necallmgr ecallmgr_maintenance authz_summary
39 |
40 | sup -necallmgr ecallmgr_maintenance channel_summary
41 |
42 | sup -necallmgr ecallmgr_maintenance channel_summary freeswitch@server.com
43 |
44 | sup -necallmgr ecallmgr_maintenance channel_details
45 |
46 | sup -necallmgr ecallmgr_maintenance channel_details 1913218612@192.168.1.133
47 |
48 | sup -necallmgr ecallmgr_maintenance sync_channels
49 |
50 | sup -necallmgr ecallmgr_maintenance sync_channels freeswitch@server.com
51 |
52 | sup -necallmgr ecallmgr_maintenance conference_summary
53 |
54 | sup -necallmgr ecallmgr_maintenance conference_summary freeswitch@server.com
55 |
56 | sup -necallmgr ecallmgr_maintenance conference_details
57 |
58 | sup -necallmgr ecallmgr_maintenance conference_details b57f3183a8f11ba31b3b5163057e2adc
59 |
60 | sup -necallmgr ecallmgr_maintenance sync_conferences
61 |
62 | sup -necallmgr ecallmgr_maintenance sync_conferences freeswitch@server.com
63 |
64 | sup -necallmgr ecallmgr_maintenance flush_node_channels freeswitch@server.com
65 |
66 | sup -necallmgr ecallmgr_maintenance flush_node_conferences freeswitch@server.com
67 |
68 | sup -necallmgr ecallmgr_maintenance flush_registrar
69 |
70 | sup -necallmgr ecallmgr_maintenance flush_registrar bea1.sip.2600hz.com
71 |
72 | sup -necallmgr ecallmgr_maintenance flush_registrar 105 bea1.sip.2600hz.com
73 |
74 | sup -necallmgr ecallmgr_maintenance registrar_summary
75 |
76 | sup -necallmgr ecallmgr_maintenance registrar_summary bea1.sip.2600hz.com
77 |
78 | sup -necallmgr ecallmgr_maintenance registrar_details
79 |
80 | sup -necallmgr ecallmgr_maintenance registrar_details bea1.sip.2600hz.com
81 |
82 | sup -necallmgr ecallmgr_maintenance registrar_details 105 bea1.sip.2600hz.com
83 |
84 | sup -necallmgr ecallmgr_maintenance flush_authn
85 |
86 | sup -necallmgr ecallmgr_maintenance flush_util
87 |
88 | ```
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/doc/kazoo/enable-cnam.md:
--------------------------------------------------------------------------------
1 | # Kazoo Enable CNAM
2 |
3 | It is possible to utilize **Kazoo** to enable **CNAM** lookups on inbound calls. This allows you to overlay Caller ID in the US with **CNAM** dips from a third-party service.
4 |
5 | ## Supported CNAM Providers
6 |
7 | * Carriers
8 | * Vitelity
9 | * Telnyx
10 | * Providers
11 | * OpenCNAM
12 | * Others possible
13 |
14 | If you provision a number using one of the carriers above, you can enable CNAM features using the [phone numbers](https://docs.2600hz.com/dev/applications/crossbar/doc/phone_numbers/) API.
15 |
16 | ## Setup OpenCNAM (or other providers)
17 |
18 | Kazoo provides a generic HTTP configuration for making CNAM dips. OpenCNAM is known to work and other providers may too, provided they return the Caller ID Name as the HTTP response body in plain text. This is handy when you provision numbers outside of Kazoo and import them.
19 |
20 | To setup the Inbound CNAM dip, use the [system config](https://docs.2600hz.com/dev/applications/crossbar/doc/system_configs/) API to create/edit the [`stepswitch.cnam`](https://github.com/2600hz/kazoo/blob/master/applications/crossbar/priv/couchdb/schemas/system_config.stepswitch.cnam.json):
21 |
22 | ```bash
23 | curl -v -X POST \
24 | -H "X-Auth-Token: {AUTH_TOKEN}" \
25 | 'http://{SERVER}:8000/v2/system_configs/stepswitch.cnam' \
26 | -d '{"data":{"default":{...}}}'
27 | ```
28 |
29 | Check the [JSON schema]((https://github.com/2600hz/kazoo/blob/master/applications/crossbar/priv/couchdb/schemas/system_config.stepswitch.cnam.json)) for the necessary fields to set in the `{...}` portion.
30 |
--------------------------------------------------------------------------------
/doc/kazoo/home-page.md:
--------------------------------------------------------------------------------
1 | ## Kazoo Home Page
2 |
3 |
4 |
5 | Welcome to **Kazoo**, the core open-source product from **2600hz**. This documentation exists to help you install and manage your own dedicated **Kazoo** cluster.
6 |
7 | Before You Begin:
8 |
9 | Who This Is For - **PLEASE READ!**:
10 |
11 | Architectural Review
12 |
13 | Design Concepts
14 |
15 | Cluster Design Patterns
16 |
17 | Cluster Deployment
18 |
19 | Configuration
20 |
21 | Maintenance
22 |
23 | Troubleshooting
24 |
25 |
--------------------------------------------------------------------------------
/doc/kazoo/kazoo-debug.md:
--------------------------------------------------------------------------------
1 | ## Kazoo Debug
2 |
3 |
4 |
5 | To be able to debug your setup you need to check the logs. The command tail `-f xxx.log` will open the `logfile` and present a live
6 | running view.
7 |
8 | Essential log files are:
9 |
10 | /var/log/2600hz/kazoo.log
11 |
12 | The main log of the **Kazoo** platform, tells you roughly what is happening on your systems in terms of **Kazoo**. It requires some getting used to, but after that its your best friend. If you need it to show you more details you can set the verbose level:
13 |
14 | /opt/kazoo/utils/sup/sup whistle_maintenance syslog_level debug
15 | (
16 | https://en.wikipedia.org/wiki/Syslog#Severity_levels
17 | )
18 | /var/log/haproxy.log
19 |
20 | Underestimated tiny log file, really descriptive. It tells you if `haproxy` is doing the needed magic, if not your system won't run nicely. Used by **Kazoo** to access mulitple systems as if they where one (**BigCOUCH** DB):
21 |
22 | /var/log/kamailio/kamailio.log
23 |
24 |
25 | **Kamailio** is your SBC, it receives registration requests (+some) and validates them:
26 |
27 | /var/log/freeswitch/debug.log
28 |
29 |
30 | **Freeswitch** should be obvious, all calls are handles by it. This file will give you a lot of info. One could also use `fs_cli` on a **Freeswitch** box:
31 |
32 | /var/log/rabbitmq/rabbit.log
33 |
34 | **Rabbitmq** is the communication tool used by **Kazoo** to communicate internally.
35 |
36 | Typical usage:
37 |
38 | User case:
39 |
40 | Inbound call fails:
41 |
42 |
43 | *Just imagine what should happen for a call to be accepted:*
44 |
45 | A call needs to be placed by someone, then delivered to **Kazoo** platform, then accepted by **Freeswitch**, then dealt with.
46 | So.. can you confirm that someone (you?) is dialing the right number? Is the number configured at the DID provider to be routed to **Kazoo**? ARE U SURE?? Ok, so lets first shutdown one FS box or tail `-f /var/log/freeswitch/debug.log` on all FS boxes.
47 | Place a test call...do you see an invite coming in that file? Yes? Great...find the CALL ID and close the log file, then `grep` CALL ID `/var/log/freeswitch/debug.log` The result of that action should be relevant log lines for that call. Check it line for line to see what happened and why it did not do what you expected.
48 |
49 | Most errors in the early stage of the **Kazoo** learning curve have to do with ACLS. Also check Inbound Calls Fail and this page
50 | No invite? That suggests that the call is not delivered to your systems. Can you confirm that someone (you?) is dialing the right number? Is the number configured at the DID provider to be routed to **Kazoo**? ARE YOU SURE? If so, please check if you dont have a firewall in place thats messing stuff up. One easy but dangerous way to test is to disable the firewall for a while. Still nothing? If you are using a SIP address when directing calls to **Kazoo**, please check DNS and DNS propagation, if unsure try to use the ip address instead of domain name. Still nothing you could check the **Kazoo** log, i dont think it will contain anything but you (actually i) never know.
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/doc/kazoo/kazoo-servermisc.md:
--------------------------------------------------------------------------------
1 | ## Install Kazoo UI
2 |
3 |
4 |
5 | How to install **Kazoo** UI in a redundant fashion, server-side. Compressing **Kazoo UI** to load faster.
6 |
7 |
--------------------------------------------------------------------------------
/doc/kazoo/kazoo-uimisc.md:
--------------------------------------------------------------------------------
1 | ## Kazoo UI
2 |
3 |
4 |
5 | Contrary to popular belief, **Kazoo UI** doesn't need to be installed anywhere in particular. In fact, since **Kazoo UI** just accesses the native **Kazoo** APIs, you can install **Kazoo UI** right on your local computer with the only requirement being a local web browser.
6 | This opens up interesting opportunities. You can develop **Kazoo UI** add-ons locally without touching your production servers which are running a different version of **Kazoo UI**, all using the same APIs. The **Kazoo** APIs can be on **Kazoo** Hosted or your own installation. This essentially allows you to heavily customize the user experience, whether or not you utilize a hosted API platform managed by you.
7 |
8 |
--------------------------------------------------------------------------------
/doc/kazoo/open-source.md:
--------------------------------------------------------------------------------
1 | # How to contribute
2 |
3 |
4 |
5 | The easiest way to get started is to fork one of the projects below on **GitHub**, make your changes, and issue a pull request to us.
6 | But I can't code (or don't know **Erlang**, **Javascript**, or **C**). How can I contribute? Our wiki is always in need of updating, expanding, clarifying, spell-checking, etc. We know the value of this work and how much it means to us when our community helps in ways that helps everyone.We also have a forum that always needs interaction. Helping answer questions, clarify details, and filing tickets for new bugs/features helps our roadmap grow in ways that are actually useful (and not what we might think are useful).
7 |
8 | Translation from English into your native tongue is also of great benefit. So much software ends up designed for use in the United States that modifying it for international use presents bigger hurdles than it should. We've known from day one that we wanted the platform to be useful around the world and have tried to not hard code aspects that are particular to the way the United States does telephony. Any help in making the platform usable in other parts of the world is greatly appreciated.
9 |
10 | Happen to have deep pockets? We are always looking for feature sponsors and are always willing to accept donations as well. T-shirts, funny photos, **2600hz** branded Kazoos and more, can be yours as a small token of our appreciation. Want Karl to sing your favorite song and post it on Youtube? Let us know and we'll figure out the dollar amount (we also accept gold bullion). Have other ideas of how you'd like to help? Let us know!
11 |
12 |
13 | ### Give me code, or give me death!
14 |
15 | ## **Kazoo** Git Repo:
16 |
17 | git clone
18 | https://github.com/2600hz/kazoo.git
19 |
20 |
21 | ## **Kazoo UI** Git Repo:
22 |
23 | git clone
24 | https://github.com/2600hz/kazoo_ui.git
25 |
26 |
27 | ## **FreeSWITCH** - custom build:
28 |
29 | git clone
30 | https://github.com/2600hz/FreeSWITCH.git
31 |
32 |
33 | ## Dependencies
34 |
35 | If you are brave enough to compile from source, please consider installing these dependencies:
36 |
37 | yum install libxslt zip unzip gcc libtool libstdc++-devel
38 | yum install gunzip #might fail, ignore it
39 |
40 |
--------------------------------------------------------------------------------
/doc/kazoo/optimize-kazoo-ui.md:
--------------------------------------------------------------------------------
1 | ## Optimize Kazoo UI
2 |
3 |
4 |
5 | How to optimize **Kazoo** UI? The optimizer will reduce the size, obfuscate and reformat all the CSS and JS file in the project.
6 |
7 |
8 | ## Prerequisites
9 |
10 | In order to use the optimizer, you will need the `requirejs` optimizer (https://github.com/jrburke/r.js). You will need to install `node` and `npm`.
11 |
12 |
13 | ## The build file
14 |
15 | The optimizer is based on a build file that will specify what options you will want to use to optimize the project. Here is the one that I used to do it:
16 |
17 | ({baseUrl: ../kazoo_ui/
18 | ,dir: optimized
19 | ,preserveLicenseComments: false,
20 |
21 | })
22 |
23 | If you want to get more information about what option is used for what I recommend taking a look at the example here:
24 | https://github.com/jrburke/r.js/blob/master/build/example.build.js
25 |
26 |
27 | ## Execution
28 |
29 | Let's say that you have put the optimizer file (r.js) and your build file (build.js) in a folder at the same level than the **Kazoo UI** folder. The command that you will need to execute is the following one:
30 |
31 | node r.js -o build.js
32 |
33 | When the execution is done, you should have a folder called "optimized" in the same folder as `r.js`.
34 |
--------------------------------------------------------------------------------
/doc/kazoo/rating-engine.md:
--------------------------------------------------------------------------------
1 | ## Kazoo Rating Engine
2 |
3 |
4 |
5 | ## Build Your Own Rating Engine
6 |
7 | Here are the steps to easily add your own rating engine to **Kazoo** (and bypass the **HotOrNot WhApp**).
8 |
9 | How calls are rated in **Kazoo**
10 |
11 | When a new call is received in the `ecallmgr` application, a rating request is published onto the AMQP bus. Any application bound for those rate request events will receive the JSON payload and can optionally respond with a rate response. The first valid response received will be the rate applied to the call.
12 |
13 |
14 | ## Rate Request JSON
15 |
16 | **Kazoo** generates a rate request payload published onto the callmgr exchange with a routing key of rate.req. The JSON payload will look something along the lines of:
17 |
18 | **Rate Request JSON:**
19 |
20 | {To-DID:+14158867900
21 | ,Call-ID:abc123def456ghi789
22 | ,Event-Category:rate
23 | ,Event-Name:req
24 | ,Msg-ID:msg_id_9876
25 | ,Server-ID:amqp_queue_name
26 | ,App-Name:sending_app
27 | ,App-Version:sending_app_ver
28 | ,Node:ecallmgr@host.com
29 | ,Account-ID:qwerty1234567890
30 | ,From-DID:+14158867915
31 | ,Options:[]
32 | ,Direction:inbound
33 |
34 | }
35 |
36 |
37 | **Description of the Rate Request JSON payload:**
38 |
39 | ```Field:Description
40 | Value : Required
41 | To-DID: The dialed number
42 | The dialed number off the INVITE
43 | Yes
44 | Call-ID: The unique identifier for this channel
45 | String: Yes
46 | Event-Category: The class of event
47 | Rate: Yes
48 | Event-Name: The name of the event
49 | Req: Yes
50 | Msg-ID: The ID of this rate request message
51 | String: Yes
52 | Server-ID: The name of the AMQP queue of the sender, empty if no response is needed
53 | String: Yes
54 | App-Name: The name of the application that published the request
55 | String: Yes
56 | App-Version: The version of the application that published the request
57 | String: Yes
58 | Node: The **Erlang** VM node name of the sender
59 | String: Yes
60 | Options: Arbitrary list of strings set by sender, usually used by receiving to filter list of applicable rates
61 | List of strings: No
62 | ```
63 |
64 | ## Direction
65 |
66 | The direction of the call, relative to Kazoo;
67 | outbound: meaning from **Kazoo** to the endpoint and
68 | inbound: meaning from the endpoint to **Kazoo**
69 | inbound/ outbound:No
70 |
71 | ``
72 | Account-ID: The **Kazoo** account ID associated with this cal (if any)
73 | String: No
74 | From-DID : The Caller ID number (if available)
75 | String: No
76 | ```
77 |
78 | ## Route Response JSON
79 |
80 | Any application which receives rate requests and wishes to respond will need to publish the response to the targeted exchange using the Server-ID from the rate request payload as the routing key. Assuming the request above, a potential response would be constructed thusly:
81 |
82 | **Rate Response JSON:**
83 |
84 | {Rate:0.05
85 | ,Call-ID:abc123def456ghi78
86 | ,Rate-Increment:60
87 | ,Rate-Minimum:60
88 | ,Discount-Percentage:0
89 | ,Surcharge:1.00
90 | ,Rate-Name:expensive_rate
91 | ,Base-Cost:1.05
92 | ,Msg-ID:msg_id_9876
93 | ,Update-Callee-ID:true
94 | ,Event-Category:rate
95 | ,Event-Name:resp
96 | ,App-Name:hotornot
97 | ,App-Version:1.0.0
98 | ,Server-ID:
99 | ,Node:whistle_apps@host.com
100 |
101 | }
102 |
103 | ```
104 |
105 | **Description of the Rate Response JSON payload:**
106 |
107 |
108 | ```Field:Description
109 | Value: Required
110 | Rate: The cost of the rate
111 | Float: Yes
112 | Call-ID: Identifier of the channel
113 | String:Yes
114 | Event-Category: Class of message
115 | Rate:Yes
116 | Event-Name: Name of the message type
117 | Resp: Yes
118 | App-Name: Name of the responding application
119 | String: Yes
120 | App-Version: Version of the responding application
121 | String: Yes
122 | Msg-ID: The ID from the request payload that identifies the request message
123 | String: Yes
124 | Node: The responder's node (useful mostly for debugging)
125 | String: Yes
126 | Server-ID: Empty, since no response to this message will be sent
127 | Rate-Increment: How many seconds before Rate is applied
128 | Integer (defaults to 60): No
129 | Rate-Minimum: Minimum number of seconds to bill the call for, regardless of call duration
130 | Integer, defaults to 60: No
131 | Discount-Percentage: Apply a discount to the cost of the call
132 | Integer: No
133 | Surcharge: Flat amount to bill the call (in addition to per-minute charges)
134 | Float: No
135 | Rate-Name: Arbitrary name for the rate
136 | String: No
137 | Base-Cost: (Rate * (Rate-Minimum div 60)) + Rate-Surcharge
138 | Float: No
139 | Update-Caller-ID: If `true`, will prepend the Callee ID name with the rate of the call
140 | Boolean, defaults to `false`: No
141 | ```
142 |
143 | ## Rate Field
144 |
145 | The `rate` fields (Rate, Rate-Increment, etc) will be set on the channel and available in the
146 | Custom-Channel-Vars of the resulting CDR. A simple formula is used to calculate the cost of the call:
147 |
148 |
149 | R = Rate
150 | RI = Rate-Increment
151 | RM = Rate-Minimum
152 | Sur = Surcharge
153 | Secs = Billing Seconds
154 | When RM `60 = Sur + ((RM / 60) * R)`
155 | When `RM = 60 = Sur + ((RM / 60) * R) + ceiling((Secs - RM) / RI) * ((RI / 60) * R)))`
156 |
157 |
158 |
--------------------------------------------------------------------------------
/doc/kazoo/service-limits.md:
--------------------------------------------------------------------------------
1 | ## Kazoo Service Limits
2 |
3 |
4 |
5 | **Kazoo** provides facilities to limit what services are being used by a particular client. Limits can involve simultaneous outbound channels, simultaneous inbound channels, total channel count, and enforcement of credit minimums.
6 |
7 | **These features can be used to provide:**
8 |
9 | 1. Two-way SIP Trunks
10 | 2. Inbound SIP Trunks
11 | 3. Per-Minute SIP Trunks
12 | 4. Per-Minute Hosted PBX Calling
13 | 5. General Resource Consumption Limits
14 | 6. Pre-Pay Cost Tracking
15 | 7. Post-Pay Cost Tracking
16 | 8. Basic Fraud Limitations (Prevent post-pay accounts from dipping
17 | too deep into their credit)
18 |
19 | **Talking Points:**
20 |
21 | 1. How to tell if a call was rated as a per-minute or a flat-rate.
22 | 2. How to tell if a call was billed properly or not (accounting table?).
23 | 3. How to double-check billing, if possible.
24 | 4. Tools to run to re-run billing, if possible, for a CDR.
25 |
26 |
--------------------------------------------------------------------------------
/doc/kazoo/service-plans.md:
--------------------------------------------------------------------------------
1 | ## Service Plans
2 |
3 | Service Plans define costs associated with various services in the system. Services figure out how many devices, trunks, users and similar
4 | features are in use for an account. Those totals are applied to one or more service plans on the account and then passed to a bookkeeper to handle the actual billing functionality.
5 |
6 | ## Use Case
7 |
8 | New guy just installed his cluster, wants to bill his clients
9 |
10 | ## Configuring a Service Plan
11 |
12 | A service plan document defines services, such as DIDs or SIP devices, which have a cost. It also defines the name of the corresponding element that will be used in your given bookkeeper (i.e. you may call DIDs in Quickbooks Phone Numbers, and therefore you need to map our name to your name). Together, these two concepts make up a service plan. The service plan document(s) is located within a reseller's account. The master account on every system is automatically considered the default reseller.
13 |
14 | ## Master / Default Service Plans
15 |
16 | Standard accounts are accounts which live underneath a reseller. By default, the master account is the first reseller in the system. For the purposes of this example, we'll assume you're creating your first account beneath your master/reseller account.
17 |
18 |
19 | **Find Your Master Account**
20 |
21 | 1. You'll need the account-ID if you don't already know it.
22 |
23 | 2. Go into the master account's database via **BigCouch**'s Futon interface
24 |
25 | 3. Create a new document
26 |
27 | 4. Add the field `pvt_type` with the value `service_plan`
28 |
29 | 5. Add a plan
30 |
31 | ```json
32 | {
33 | "devices": {
34 | "_all": {
35 | "as": "sip_devices",
36 | "cascade": "true",
37 | "name": "SIP Device",
38 | "rates": {
39 | "100": 149.95,
40 | "20": 24.95,
41 | "5": 0,
42 | "50": 49.95
43 | }
44 | }
45 | },
46 | "limits": {
47 | "inbound_trunks": {
48 | "name": "Inbound Trunk",
49 | "rate": 19.99
50 | },
51 | "twoway_trunks": {
52 | "name": "Two-Way Trunk",
53 | "rate": 29.99
54 | }
55 | },
56 | "number_services": {
57 | "cnam": {
58 | "activation_charge": 2,
59 | "name": "CNAM Update"
60 | },
61 | "e911": {
62 | "discounts": {
63 | "single": {
64 | "rate": 5
65 | }
66 | },
67 | "name": "E911 Service",
68 | "rate": 5
69 | },
70 | "port": {
71 | "activation_charge": 5,
72 | "name": "Port Request"
73 | }
74 | },
75 | "phone_numbers": {
76 | "did_us": {
77 | "cascade": "false",
78 | "discounts": {
79 | "cumulative": {
80 | "maximum": 2,
81 | "rate": 0.5
82 | }
83 | },
84 | "name": "US DID",
85 | "rate": 1
86 | },
87 | "tollfree_us": {
88 | "cascade": "true",
89 | "minimum": 10,
90 | "name": "US Tollfree",
91 | "rate": 5
92 | }
93 | }
94 | }
95 | ```
96 |
97 | **Reseller Service Plans**
98 |
99 | **Service Plan Minimums**
100 |
101 | **List Available Service Plans**
102 | ```bash
103 | curl -v -X GET -H "X-Auth-Token: $AUTH_TOKEN" "http://localhost:8000/v2/accounts/$ACCOUNT_ID/services/available" | jq
104 | ```
105 | **Retrive currently assigned service plan**
106 | ```
107 | curl -v -X GET -H "X-Auth-Token: $AUTH_TOKEN" "http://localhost:8000/v2/accounts/$ACCOUNT_ID/services" | jq
108 | ```
109 | **Service Plan Summary**
110 | ```
111 | curl -v -X GET -H "X-Auth-Token: $AUTH_TOKEN" "http://localhost:8000/v2/accounts/$ACCOUNT_ID/services/summary" | jq
112 | ```
113 | **Assigning Service Plan to an Account**
114 | ```
115 | curl -v -X POST -H "X-Auth-Token: $AUTH_TOKEN" "http://localhost:8000/v2/accounts/$ACCOUNT_ID/services/$PLAN_ID" | jq
116 | ```
117 | **Remove Service Plan from Account**
118 | ```
119 | curl -v -X DELETE -H "X-Auth-Token: $AUTH_TOKEN" "http://localhost:8000/v2/accounts/$ACCOUNT_ID/services/$PLAN_ID" | jq
120 | ```
121 |
122 | **Promoting Account to Reseller Status**
123 | ```
124 | curl -s -X PUT -H "X-Auth-Token: {AUTH_TOKEN}" http://localhost:8000/v2/accounts/{ACCOUNT_ID}/reseller
125 | ```
126 | **Demote Account from Reseller Status**
127 | ```
128 | curl -s -X DELETE -H "X-Auth-Token: {AUTH_TOKEN}" http://localhost:8000/v2/accounts/{ACCOUNT_ID}/reseller
129 | ```
130 | **Setting the default / global service plan**
131 |
132 | **Checking if someone is properly setup as a reseller?**
133 |
134 | **APIs for any of the above (now or future)**
135 |
136 | **What does default_service_plan do?**
137 |
138 | **How to check that a bookkeeper is loaded/running?**
139 | To check if braintree app is running
140 | ```
141 | sup kapps_controller list_apps
142 | ```
143 | Braintree app should be in this list.
144 |
145 | **What happens if a bookkeeper is not working/loaded/running?**
146 |
147 | ## Advanced Features
148 |
149 | It may be useful to have a reseller account with subaccounts, who in turn have their own subaccounts, all billing back to the reseller account. An account's reseller is determined by looking at each parent until the first account with a reseller flag is found. If no such account is found, the master account is used.
150 |
151 |
152 | ## IMMEDIATE ACTION AFTER CHANGE:
153 |
154 | USER ADDS DEVICE
155 |
156 | DEVICES ARE RE-COUNTED
157 |
158 | SERVICES DATABASE IS UPDATED WITH LATEST COUNT
159 |
160 | ACCOUNT IS MARKED AS DIRTY
161 |
162 | ## PERIODIC MAINTENANCE:
163 |
164 | SCAN FOR DIRTY ACCOUNTS
165 |
166 | APPLY SERVICE PLAN TO ACCOUNT SERVICES
167 |
168 | PASS THE LIST OF BILLABLE ITEMS TO THE BOOKKEEPER
169 |
170 | IF CUSTOMER IS PART OF A RESELLER, DIRTY THE RESELLER'S ACCOUNT
171 |
172 | ## BOOKKEEPER:
173 |
174 | TAKE NORMALIZED LIST OF ITEMS
175 |
176 | PASS TO BOOKKEEPER SPECIFIC LOGIC (Could be WHMCS, Braintree, Stripe, etc.)
177 |
178 | RETURNS ACCOUNT STATUS (GOOD STANDING or ERROR)
179 |
--------------------------------------------------------------------------------
/doc/kazoo/sip-flowchart.md:
--------------------------------------------------------------------------------
1 | ## Kazoo SIP Flowchart
2 |
3 |
4 |
5 | *These flowcharts are not meant to be exhaustive; merely guides to helping diagnose where a call veered off the tracks and failed.*
6 |
7 | Failed does not mean the call wasn't answered or a busy signal was received; those are successful in that the call was placed properly and an acceptable end of the call was encountered. Failure, in this case, are ends of the SIP dialogue that are unexpected or not supposed to happen. Examples include, but aren't limited to, 404 Not Found or 403 Forbidden.
8 |
9 | For more response codes and more in-depth illustrations of SIP dialogues - Wikipedia is a great resource.
10 |
--------------------------------------------------------------------------------
/doc/kazoo/tdm.md:
--------------------------------------------------------------------------------
1 | ## Kazoo and TDM
2 |
3 |
4 |
5 | **Kazoo** allows you to connect your **FreeSWITCH** servers to TDM-based networks via PRIs or other digital circuits. Using cards
6 | supporting the **FreeSWITCH FreeTDM** system you can program **Kazoo** to utilize hardware inside **FreeSWITCH** servers to call via those
7 | circuits. The current **Kazoo FreeTDM** support is fairly limited. You must have a TDM card installed, with similar capacity, in each system where calls are to be placed. To configure the user of TDM circuits, add a document such as the sample below to your offnet or carriers record:
8 |
9 | ```
10 | {_id: 23c1c9ae35fc7b7318d6128af00009bb,
11 | pvt_type: resource,
12 | name: FreeTDM Pretend Card,
13 | enabled: true,
14 | flags: [ ],
15 | weight_cost: 60,
16 | rules: [^\\+1(\d{10})$],
17 | gateways: [{server: fs-tdm.2600hz.com,
18 | prefix: 1, suffix: ,
19 | codecs:[PCMU], progress_timeout: 8,
20 | enabled: false, span: 1, invite_format: e164,
21 | endpoint_type: freetdm, channel_selection: ascending} ]
22 |
23 | }
24 | ```
25 |
26 |
27 |
--------------------------------------------------------------------------------
/doc/mkdocs/index.md:
--------------------------------------------------------------------------------
1 | Everything you need to know to run and manage 2600hz software.
2 |
3 |
--------------------------------------------------------------------------------
/doc/monster/login-issues.md:
--------------------------------------------------------------------------------
1 | ## Login Issues
2 |
3 |
4 |
5 | 1. User can't login: Check that the API URL set up in the JS / `config.js` is correct.
6 |
7 | 2. User can login but lands on a white page: Check that the API URL of the apps are setup correctly in the database. Apps are defined in the admin account database, in the `app_store` view. If you need to update these documents, refresh the views:
8 |
9 | `sup kapps_maintenance blocking_refresh`
10 |
11 |
12 | ## Phone Numbers Issues
13 |
14 | 1. User can't search/buy/list numbers: Make sure that the correct `phonebook_url` are defined properly in the `system_configs`, `crossbar.phone_numbers` and `number_manager.other`.
15 |
--------------------------------------------------------------------------------
/doc/monster/optimize-monster.md:
--------------------------------------------------------------------------------
1 | ## Optimize Kazoo UI
2 |
3 |
4 |
5 | How to optimize **Kazoo UI**?
6 |
7 |
8 | The optimizer will reduce the size, obfuscate and reformat all the CSS and JS file in the project
9 |
10 |
11 | ## Prerequisites
12 |
13 | In order to use the optimizer, you will need... the `requirejs` optimizer (https://github.com/jrburke/r.js).
14 | You will need to install `node` and `npm`.
15 |
16 |
17 | ## The Build file
18 |
19 | The optimizer is based on a build file that will specify what options you will want to use to optimize the project.
20 | Here is the one that I used to do it:
21 |
22 |
23 | {
24 |
25 | baseUrl: monsterToOptimized/
26 | ,mainConfigFile: monsterToOptimized/js/main.js
27 | ,dir: optimized
28 | ,findNestedDependencies: true,
29 | ,preserveLicenseComments: false
30 | ,removeCombined: true
31 | ,modules: [{ name: js/main
32 | ,exclude: [config]},
33 |
34 |
35 | {
36 |
37 | name: apps/common/app
38 | ,exclude: [bootstrap-switch
39 | ,toastr
40 | ,jquery
41 | ,monster
42 | ,timepicker
43 | ,underscore
44 | ,ddslick
45 | ]},
46 |
47 |
48 | {
49 |
50 | name: apps/voip/app
51 | ,exclude: [ jstz
52 | ,monster-timezone
53 | ,toastr
54 | ,jquery
55 | ,mask
56 | ,monster
57 | ,timepicker
58 | ,underscore
59 | ,chosen
60 | ,chart
61 | ]},
62 |
63 |
64 | {
65 |
66 | name: apps/callflows/app
67 | ,exclude: [
68 | ,jquery
69 | ,monster
70 | ,underscore
71 | ,chosen
72 | ,mask
73 | ,monster-timezone
74 | ,slider
75 |
76 | ]}
77 |
78 | ]}
79 |
80 | If you want to get more information about what option is used for what I recommend taking a look at the example here:
81 |
82 | https://github.com/jrburke/r.js/blob/master/build/example.build.js
83 |
84 |
85 | ## Execution
86 |
87 | Let's say that you have put the optimizer file `r.js` and your build file `build.js` in a folder at the same level than the **Kazoo UI** folder. The command that you will need to execute is the following one:
88 |
89 | node r.js -o build.js
90 |
91 | When the execution is done, you should have a folder called 'optimized' in the same folder as `r.js` (Note: On Windows, you might have to type `r.js.cmd` instead of `r.js`)
92 |
--------------------------------------------------------------------------------
/doc/operation/cluster-health.md:
--------------------------------------------------------------------------------
1 | ## Cluster Health
2 |
3 |
4 |
5 | These instructions assume you are running as `root`. All services MUST be working as indicated in order to have a properly running **Kazoo** platform.
6 |
7 |
8 | ## FreeSWITCH
9 |
10 | Is **FreeSWITCH** running?
11 | ```
12 | service freeswitch status
13 |
14 | freeswitch(pid:xxxx): up
15 | ```
16 | If not then:
17 |
18 | `service freeswitch start`
19 |
20 | Is **FreeSWITCH** Connected?
21 |
22 | **FreeSWITCH** must be connected to the rest of the platform. You can check this from within **FreeSWITCH** itself. Enter the
23 |
24 | **FreeSWITCH** CLI and check for erlang listener(s). You should have at least one:
25 | ```
26 | cli -x
27 |
28 | erlang listeners
29 | ```
30 | You should see at least one of your other servers listed. If you don't, or there are no listeners, then **FreeSWITCH** is running by `ecallmgr` is not connected to it.
31 |
32 |
33 | ## ECallMgr
34 |
35 | Is **ECallMgr** Running?
36 |
37 | **ECallMgr** connects the Kazoo platform with all **FreeSWITCH** servers. It is the primary link between **FreeSWITCH** and the rest of the platform.
38 |
39 | `service ecallmgr status
40 |
41 | [freeswitch@fs001.yourserver.com,
42 |
43 | freeswitch@fs002.yourserver.com]`
44 |
45 | This command should return a list of **FreeSWITCH** nodes which **ECallMgr** is connected to, in JSON format.
46 |
47 | If it does not, try restarting `ECallMgr`:
48 |
49 | `service ecallmgr restart`
50 |
51 | Check **RabbitMQ** status
52 |
53 | **RabbitMQ** provides the glue between **FreeSWITCH** and the **Kazoo** Applications:
54 | `
55 | service rabbitmq-server status`
56 |
57 | That command should return something like:
58 | ```
59 | #Status of node rabbit@mydomain.com...
60 |
61 | [{pid,2049
62 | },
63 |
64 | { running_applications,[{rabbit,
65 |
66 | RabbitMQ, 2.7.0 },
67 |
68 | {os_mon, CPO CXC 138 46, 2.2.6},
69 |
70 | {sasl, SASL CXC 138 11, 2.1.9.4},
71 |
72 | {mnesia, MNESIA CXC 138 12, 4.4.19},
73 |
74 | {stdlib,ERTS CXC 138 10, 1.17.4},
75 |
76 | {kernel,ERTS CXC 138 10,2.14.4}]},
77 |
78 | {os,{unix,linux}},
79 |
80 | {erlang_version,
81 |
82 | Erlang R14B03 (erts-5.8.4) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:30] [kernel-poll:true]\n},
83 |
84 | {memory,[{total, 26165880},
85 |
86 | {processes, 10842712},
87 |
88 | {processes_used, 10828488},
89 |
90 | {system, 15323168},
91 |
92 | {atom, 1122017},
93 |
94 | {atom_used, 1116886},
95 |
96 | {binary, 115952},
97 |
98 | {code, 11271185},
99 |
100 | {ets, 865008}]},
101 |
102 | {vm_memory_high_watermark,0.3999999997516473},
103 |
104 | {vm_memory_limit, 322122547}]`
105 |
106 | ...done.
107 |
108 | #If not then:
109 |
110 | `# service rabbitmq-server restart`
111 | ```
112 |
113 | ## Kazoo Applications
114 |
115 | `# service whapps status`
116 |
117 | Should give you something like: Searching for running **WhApps** on `whistle_apps@mydomain.com`
118 | ```
119 | [cdr,sysconf,conference,registrar,hangups,media_mgr,crossbar,callflow,stepswitch]
120 | ```
121 | If it does not, try restarting it.
122 |
123 | `service whapps restart`
124 |
125 | Some of these are optional and some are mandatory. I believe **Crossbar** is necessary for **Winkstart** to work. If **Crossbar** is not there you can try running
126 |
127 | `whapps_maintenance:refresh().`
128 |
129 | from the 'Some Useful Commands' section of this wiki.
130 |
131 |
132 | ## HAProxy
133 |
134 | `# service haproxy status`
135 |
136 | haproxy (pid xxxx) is running...and if not
137 |
138 | `# service haproxy restart`
139 |
140 |
141 | ## Check BigCouch
142 |
143 | Assuming localhost
144 |
145 | `# curl localhost: 5984
146 |
147 | { couchdb: Welcome, version: 1.1.1, bigcouch: 0.4.0}`
148 |
149 | if not then check and double check your haproxy config and status and try:
150 |
151 | `# service bigcouch restart`
152 |
153 |
154 |
--------------------------------------------------------------------------------
/doc/operation/ets-persist.md:
--------------------------------------------------------------------------------
1 | ## ETS Persistence
2 |
3 |
4 |
5 | ## Don't lose your data
6 |
7 | When using ETS tables, when the owner dies, typically the ETS table will be deleted as well. On some occasions, this is not desired behaviour. See Steve Vinoski's blog article for more.
8 |
9 |
10 | ## Kazoo's Approach
11 |
12 | We have an implementation of an ETS manager server process that will handle creating the ETS table, handing off control to the process that will actually use the table for work, receiving notifications when that process dies, and handing off control once a replacement process is available.
13 |
14 |
15 | ## How it works
16 |
17 | If you navigate over to `kazoo_etsmgr_srv.erl`, you will find the `gen_server` code to manage an ETS table. To make use of the server, here's the typical steps involved:
18 |
19 | Define the ETS properties
20 |
21 | Define the ETS table's name
22 |
23 | Define the `find_me_function`, a function that returns either the `PID` of the new process to pass control to, or `undefined` if no process is ready to assume control yet.
24 |
25 | Define the table_options; see `ets:new/2`for those.
26 |
27 | Define the `gift_data`; typically this is ignored.
28 |
29 | Start the manager process in the supervisor
30 |
31 | Handle gaining control of the ETS table from the manager process
32 |
33 | **How it might look**
34 |
35 | This might go in your `gen_server`, `gen_listener`, etc.
36 |
37 | 1. Defining the ETS properties
38 | ```
39 | -export([table_id/0
40 | ,table_options/0
41 | ,find_me_function/0
42 | ,gift_data/0
43 | ]).
44 |
45 | table_id() -
46 | ?MODULE. %% Any atom will do
47 | table_options() -[].
48 | find_me_function() -
49 | whereis(?MODULE).
50 | gift_data() -
51 | ok.
52 | #This might go in your application's supervisor
53 |
54 | #Start the manager process
55 |
56 | -define(CHILDREN, [?WORKER_ARGS(kazoo_etsmgr_srv, [[{
57 | table_id, your_srv:table_id()}
58 | ,{
59 |
60 | table_options, your_srv:table_options()}
61 | ,{find_me_function, fun your_srv:find_me_function/0},
62 | {
63 | gift_data
64 | ,your_srv:gift_data()}]])
65 | ,...
66 |
67 | ]).
68 |
69 | ```
70 | In your `gen_server`/`gen_listener`, handle receiving control of the ETS table
71 |
72 | **Gain control**
73 |
74 | `handle_info({
75 | ETS-TRANSFER
76 | ,TableId, From, GiftData}, State) -
77 | #Now this process can write to the ETS table
78 | {noreply, State};`
79 |
80 | Now your process should be all set to write to the ETS table (and you can do the reads in the calling processes to parallelize reading, unless you want to serialize the reads through the server as well).
81 |
--------------------------------------------------------------------------------
/doc/operation/login-noapps.md:
--------------------------------------------------------------------------------
1 | ## Login Kazoo UI
2 |
3 |
4 |
5 | If you login to your **Kazoo** UI but no applications appear at the top of the page, your user or your config.js have mismatched API URLs. For security and validation, when you login the system checks to make sure the API you are logging into matches the API you are requesting apps from. If they don't, things won't work right (without special CORS headers - that's an advanced topic).
6 |
7 | To fix this issue, follow these steps:
8 |
9 |
10 | ## Step 1: Identify the Authentication URL
11 |
12 | In your Kazoo UI's HTML folders there is a folder named config and a file named config.js. Inside that file is a configuration section which includes a default auth app which specifies the API you are authenticating against.
13 |
14 | winkstart.apps = {
15 | auth: { api_url: http://YOUR.SERVER.NAME.COM:8000/v1 }
16 | };
17 |
18 | Note the `api_url` that is set.
19 |
20 |
21 | ## Step 2: Identify the User's Apps
22 |
23 | For each user that logs in they have a configured list of apps. These apps also utilize an API URL. If you are running **Kazoo UI** on your own server you'll want users to be utilizing the same API they authenticated with.
24 | To find the user's app list, take the following steps:
25 |
26 | Login to Futon (your **CouchDB**'s graphical user interface) on port 5984 on your server.
27 |
28 | http://YOUR.SERVER.NAME.COM:5984/_utills/
29 |
30 | Click on the correct account ID to enter your account database. Accounts are formatted `account/22/33/4567890456789045678904567890`
31 | Once inside the account database, on the top right corner of the screen is a drop-down with all the available views. Click on the drop-down and select `users/ crossbar`
32 |
33 | Verify that the API URL for your App matches the API URL you logged in with (in Step 1)
34 |
35 | If you make a change, make sure you logout and log back in as the list of Apps is cached on your browser.
36 |
37 | You can add the complete list of apps manually, like this:
38 |
39 | {
40 | voip: {
41 | label: Hosted PBX,
42 | icon: phone,
43 | api_url: http://YOUR.SERVER.NAME.COM:8000/v1,
44 |
45 | ui_flags: {
46 | provision_admin: true,
47 | super_duper_admin: true
48 | },
49 |
50 | default: false
51 | },
52 |
53 | pbxs: {
54 | label: PBX Connector,
55 | icon: pbx,
56 | api_url: http://YOUR.SERVER.NAME.COM:8000/v1,
57 | default: false
58 | },
59 |
60 | numbers: {
61 | label: Number Manager,
62 | icon: menu1,
63 | api_url: http://YOUR.SERVER.NAME.COM:8000/v1,
64 | default: false
65 | },
66 |
67 | accounts: {
68 | label: Accounts,
69 | icon: account,
70 | api_url: http://YOUR.SERVER.NAME.COM:8000/v1,
71 | default: true
72 | },
73 |
74 | developer: {
75 | id: developer,
76 | label: Developer,
77 | icon: connectivity,
78 | desc: API Developer Tool,
79 | api_url: http://YOUR.SERVER.NAME.COM:8000/v1,
80 | default: false
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/doc/operation/monitoring.md:
--------------------------------------------------------------------------------
1 | ## Monitoring Overview
2 |
--------------------------------------------------------------------------------
/doc/operation/shared_line_appearance.md:
--------------------------------------------------------------------------------
1 | # Shared Line Appearance (SLA)
2 |
3 | Legacy PBXes often had a feature called **Shared Line Appearance** for incoming calls. The functionality basically allowed multiple phones to have a line key tied to an extension or DID and offered several features:
4 |
5 | - Incoming calls would ring all configured phones simultaneously
6 | - When a phone answered the call, the status light would turn green; on the other phones, the status light would turn red
7 | - If the caller is placed on hold, all phones' (answering or not) status lights will blink red
8 | - Any phone with SLA can pickup the on-hold call
9 | - When the call completes, all status lights turn off.
10 |
11 | ## Simulating SLA
12 |
13 | Simulating most of SLA on a Kazoo system is possible. Let's take a look at how this might be achieved.
14 |
15 | ### Incoming calls ring all devices
16 |
17 | This is pretty straight-forward. In Kazoo, one of the callflow actions is a [ring group](https://docs.2600hz.com/dev/applications/callflow/doc/ring_group/). Put any endpoints ([`devices`](https://docs.2600hz.com/dev/applications/crossbar/doc/devices/), [`users`](https://docs.2600hz.com/dev/applications/crossbar/doc/users/), or [`groups`](https://docs.2600hz.com/dev/applications/crossbar/doc/groups/)) into the ring group and all calls to the callflow will ring the endpoints according to the strategy provided.
18 |
19 | ### Status lights
20 |
21 | Kazoo allow updating a pre-defined `presence_id` to with BLF updates. You can set this `presence_id` on the `device` or `user` documents, or you can use the `manual_presence` callflow action to toggle this. Configure the phones' BLF light to subscribe for this `presence_id` value to have it update during calls.
22 |
23 | #### Placing on hold for others
24 |
25 | The closest way to put a call on hold so others could pick it up is using [`call parking`](https://docs.2600hz.com/dev/applications/callflow/doc/park/). Rather than using the hold button on the phone, the answering device can transfer the caller to a parking slot. Once parked, any device that knows the slot number can pick up the call.
26 |
27 | ## Example SLA simulation
28 |
29 | Consider the typical executive with an administrative assistant. The assistant's phone has a line key that will ring when the executive is called. The easiest way to do this is create two devices in Kazoo and assign them to the executive's Kazoo user.
30 |
31 | ### Create the assistant
32 |
33 | 1. Create the assitant's device
34 | ```shell
35 | curl -X PUT \
36 | -H "X-Auth-Token: $AUTH_TOKEN" \
37 | -d '{"data":{"name":"Assistant Device", "sip":{"username":"assistant", "password":"to_the_stars"}}}' \
38 | http://{SERVER}:8000/v2/accounts/$ACCOUNT_ID/devices
39 | ```
40 | ```json
41 | {
42 | "data":{
43 | "id":"{ASSISTANT_DEVICE_ID}"
44 | ,...
45 | }
46 | ,...
47 | }
48 | ```
49 |
50 | ### Create the executive
51 |
52 | 1. [Create a user](https://docs.2600hz.com/dev/applications/crossbar/doc/users/) for the executive. Be sure to include `presence_id="EXT"` in the user object - this is what BLF lights will be tied to when setting up presence.
53 | ```shell
54 | curl -X PUT \
55 | -H "X-Auth-Token: {AUTH_TOKEN}" \
56 | -d '{"data":{"first_name":"Exec", "last_name":"Utive", "presence_id":"1000"}}'
57 | http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users
58 | ```
59 | ```json
60 | {
61 | "data":{
62 | "id":"{EXECUTIVE_USER_ID}"
63 | ,...
64 | }
65 | ,...
66 | }
67 | ```
68 | 2. [Create a device](https://docs.2600hz.com/dev/applications/crossbar/doc/devices/) for the executive.
69 | ```shell
70 | curl -X PUT \
71 | -H "X-Auth-Token: $AUTH_TOKEN" \
72 | -d '{"data":{"name":"Executive Device", "owner_id":"{EXECUTIVE_USER_ID}", "sip":{"username":"executive", "password":"high_roller"}}}' \
73 | http://{SERVER}:8000/v2/accounts/$ACCOUNT_ID/devices
74 | ```
75 | ```json
76 | {
77 | "data":{
78 | "id":"{EXECUTIVE_DEVICE_ID}"
79 | ,...
80 | }
81 | ,...
82 | }
83 | ```
84 | 3. [Create the callflow](https://docs.2600hz.com/dev/applications/crossbar/doc/callflows/) using the [ring group](https://docs.2600hz.com/dev/applications/callflow/doc/ring_group/) action to ring both the executive's and assistant's phones. This will also cause a BLF update to `presence_id`@`account.realm` to update the assistant's BLF key.
85 | ```shell
86 | curl -X PUT \
87 | -H "X-Auth-Token: $AUTH_TOKEN" \
88 | -d '{"data":{"numbers":["1000"], "flow":{"module":"ring_group","data":{"endpoints":[{"id":"{EXECUTIVE_USER_ID}", "endpoint_type":"user"}, {"id":"{ASSISTANT_DEVICE_ID}", "endpoint_type":"device"}]}}}}' \
89 | http://{SERVER}:8000/v2/accounts/$ACCOUNT_ID/callflows
90 | ```
91 | ```json
92 | {
93 | "data":{
94 | "id":"{EXECUTIVE_CALLFLOW_ID}"
95 | ,...
96 | }
97 | }
98 | ```
99 |
100 | Now calls to extension 1000 should ring both the executive and the assistant devices.
101 |
102 | ### Create the call park/pickup callflow
103 |
104 | Create a callflow, `*4{presence_id}`, that will have the [`park`](https://docs.2600hz.com/dev/applications/callflow/doc/park/) callflow action. This will be used by the BLF key to simulate the hold/pickup of SLA. You should set the `action` to `auto` and the `slot` to `presence_id`.
105 | ```shell
106 | curl -X PUT \
107 | -H "X-Auth-Token: $AUTH_TOKEN" \
108 | -d '{"data":{"patterns":["*4(\\d+)"], "flow":{"module":"park","data":{"action":"auto"}}}}' \
109 | http://{SERVER}:8000/v2/accounts/$ACCOUNT_ID/callflows
110 | ```
111 | ```json
112 | {
113 | "data":{
114 | "id":"{PARK_CALLFLOW_ID}"
115 | ,...
116 | }
117 | }
118 | ```
119 |
120 | `auto` will retrieve a call if one is parked or park the call if the slot is empty.
121 |
122 | ### Create the BLF key
123 |
124 | Create a BLF key configuration on the assistant's phone to:
125 |
126 | a. The "value" (or equivalent) will be `presence_id`
127 | b. The "extension" (or equivalent) will be `*4{presence_id}`
128 |
129 | This will light up with the corresponding call.
130 |
131 | When the assistant puts the call on hold, the BLF can be used to pickup the call.
132 |
--------------------------------------------------------------------------------
/doc/provisioner/README.md:
--------------------------------------------------------------------------------
1 | # Provisioner by 2600Hz
--------------------------------------------------------------------------------
/doc/security/iptables.md:
--------------------------------------------------------------------------------
1 | ## Setting up IPTABLES
2 |
3 |
4 |
5 | For your **Kazoo** / **Kamailio** servers create a file called `secure.sh`. Paste the below script into `secure.sh` and modify to fit your environment.
6 |
7 | After saving the file you need to make it executable.
8 | `chmod +x secure.sh`
9 |
10 | Now let's run our new script.
11 | `./secure.sh`
12 |
13 |
14 | ## IPTABLES - Kazoo Server
15 | ```
16 | #!/bin/bash
17 | # cwd=/etc/sysconfig/
18 | #
19 | # flush all existing rules and chains
20 | iptables -F
21 | iptables -X
22 | # allow inbound ssh connection on external/public interface
23 | iptables -A INPUT -p tcp --dport 22 --sport 1024:65535 -m state --state NEW,ESTABLISHED -j ACCEPT
24 | # set default policies (allow any outbound, block inbound, restrict forwarding between interfaces)
25 | iptables -P INPUT DROP
26 | iptables -P FORWARD DROP
27 | iptables -P OUTPUT ACCEPT
28 | # Allow TCP 80 and 443 for Winkstart if you installed KAZOO-UI
29 | iptables -A INPUT -p tcp --dport 80 -j ACCEPT
30 | iptables -A INPUT -p tcp --dport 443 -j ACCEPT
31 | # Allow RTP traffic
32 | iptables -A INPUT -p udp --dport 16384:32768 -j ACCEPT
33 | # Allow KAMAILIO traffic
34 | iptables -A INPUT -p tcp --dport 5060 -j ACCEPT
35 | iptables -A INPUT -p tcp --dport 7000 -j ACCEPT
36 | iptables -A INPUT -p udp --dport 5060 -j ACCEPT
37 | iptables -A INPUT -p udp --dport 7000 -j ACCEPT
38 | # allow all inbound traffic coming in on loopback and the internal/private interfaces
39 | #iptables -A INPUT -i eth0 -j ACCEPT
40 | iptables -A INPUT -i lo -j ACCEPT
41 | # allow your home / office ip
42 | iptables -A INPUT -s "XXX.XXX.XXX.XXX" -j ACCEPT # YOUR STATIC IP
43 | #iptables -A INPUT -s "" -j ACCEPT # whatever IP u want if u want someone else to see the db
44 | #PUBLIC IP ADDRESSES OF YOUR SERVERS - REPLACE X'S
45 | iptables -A INPUT -s "XXX.XXX.XXX.XXX" -j ACCEPT # - FREESWITCH LOCATION-1 SERVER-1
46 | iptables -A INPUT -s "XXX.XXX.XXX.XXX" -j ACCEPT # - FREESWITCH LOCATION-2 SERVER-1
47 | iptables -A INPUT -s "XXX.XXX.XXX.XXX" -j ACCEPT # - BIGCOUCH-DB LOCATION-1 SERVER 001
48 | iptables -A INPUT -s "XXX.XXX.XXX.XXX" -j ACCEPT # - BIGCOUCH-DB LOCATION-1 SERVER 002
49 | iptables -A INPUT -s "XXX.XXX.XXX.XXX" -j ACCEPT # - BIGCOUCH-DB LOCATION-2 SERVER 001
50 | iptables -A INPUT -s "XXX.XXX.XXX.XXX" -j ACCEPT # - BIGCOUCH-DB LOCATION-2 SERVER 002
51 | iptables -A INPUT -s "XXX.XXX.XXX.XXX" -j ACCEPT # - WHAPPS/KAZOO LOCATION-1 SERVER-1
52 | iptables -A INPUT -s "XXX.XXX.XXX.XXX" -j ACCEPT # - WHAPPS/KAZOO LOCATION-2 SERVER-1
53 | #INTERNET / PRIVATE NETWORK IP ADDRESSES OF YOUR SERVERS
54 | iptables -A INPUT -s "XXX.XXX.XXX.XXX" -j ACCEPT # - FREESWITCH LOCATION-1 SERVER-1
55 | iptables -A INPUT -s "XXX.XXX.XXX.XXX" -j ACCEPT # - FREESWITCH LOCATION-2 SERVER-1
56 | iptables -A INPUT -s "XXX.XXX.XXX.XXX" -j ACCEPT # - BIGCOUCH-DB LOCATION-1 SERVER 001
57 | iptables -A INPUT -s "XXX.XXX.XXX.XXX" -j ACCEPT # - BIGCOUCH-DB LOCATION-1 SERVER 002
58 | iptables -A INPUT -s "XXX.XXX.XXX.XXX" -j ACCEPT # - BIGCOUCH-DB LOCATION-2 SERVER 001
59 | iptables -A INPUT -s "XXX.XXX.XXX.XXX" -j ACCEPT # - BIGCOUCH-DB LOCATION-2 SERVER 002
60 | iptables -A INPUT -s "XXX.XXX.XXX.XXX" -j ACCEPT # - WHAPPS/KAZOO LOCATION-1 SERVER-1
61 | iptables -A INPUT -s "XXX.XXX.XXX.XXX" -j ACCEPT # - WHAPPS/KAZOO LOCATION-2 SERVER-1
62 | # block traffic coming into db unless ACCEPTED in INPUT above which 8server setup IP's are placed in with home/office IP's above.
63 | iptables -A INPUT -p tcp --dport 15984 -j DROP
64 | iptables -A INPUT -p tcp --dport 15986 -j DROP
65 | # Allow TCP 8000 and 8443 for Crossbar
66 | iptables -A INPUT -p tcp --dport 8000 -j ACCEPT
67 | iptables -A INPUT -p tcp --dport 8443 -j ACCEPT
68 | # allow inbound traffic for established connections on external/public interface
69 | iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
70 | # block packets coming in with invalid source ips
71 | iptables -A INPUT -s 10.0.0.0/8 -j DROP
72 | iptables -A INPUT -s 172.16.0.0/12 -j DROP
73 | iptables -A INPUT -s 192.168.0.0/16 -j DROP
74 | iptables -A INPUT -s 224.0.0.0/4 -j DROP
75 | iptables -A INPUT -s 240.0.0.0/5 -j DROP
76 | iptables -A INPUT -s 0.0.0.0/8 -j DROP
77 | iptables -A INPUT -s 169.254.0.0/16 -j DROP
78 | iptables -A INPUT -s 127.0.0.0/8 -j DROP
79 | # ICMP
80 | iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/sec -j ACCEPT
81 | # SYN flood limiter
82 | iptables -A INPUT -p tcp --syn -m limit --limit 5/s -j ACCEPT
83 | # catch-all for end of rules
84 | # LOG and DENY other traffic to help identify additional filters required
85 | iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level debug
86 | iptables -A INPUT -j REJECT --reject-with icmp-host-prohibited
87 | # Save settings
88 | #
89 | # On CentOS / Fedora this will output the current IPTables to the stdout, which we can pipe to a file that sets these on boot
90 | iptables-save > /etc/sysconfig/iptables
91 | #
92 | # List rules
93 | #
94 | iptables -L -v
95 |
96 | ```
97 |
--------------------------------------------------------------------------------
/doc/whapp/build.md:
--------------------------------------------------------------------------------
1 | ## Build Your Own WhApp
2 |
3 |
4 |
5 | ## WhApps
6 |
7 | **WhApps** are built to be self-contained units of functionality, varying in scope from a registrar that listens and responds to authentication requests and lookups from **Kazoo**, to a full-blown call center system handling agents, queues, etc. While they do not depend on each other for functionality, some are quite fundamental to the operation of normal telephony services, and therefore we enable them by default. Of course, you are free to write other **WhApps** to replace the functionality provided.
8 |
9 |
10 | ## The WhApp Container
11 |
12 | All code is referenced from: ` $KAZOO/whistle_apps/ directory`
13 |
14 | Starting the container is as simple as `running ./start.sh` from the applications directory. With no additional arguments, the start script will start an **Erlang** Virtual Machine named `whistle_apps`. You can start multiple VMs by passing unique values as an argument to the script (running more than one VM on a single physical server could help increase throughput, depending on the scenario and circumstances).
15 |
16 | Once started, a control script is available to interact with the container in a rudimentary way. `whistle_apps_ctl` has a couple options for managing what **WhApps** are running on the VM: `start_app`, `stop_app`, and `running_apps`.
17 |
18 | `start_app`: takes one parameter, the name of the **WhApp** to start, if its not already started.
19 |
20 | `stop_app`: takes one parameter, the name of the **WhApp** to stop, if it has been started.
21 |
22 | `running_apps`: takes no parameters, returns a list of known running **WhApps**.
23 |
24 |
25 | ## CouchDB
26 |
27 | We use an abstraction layer on top of CouchDB that can be configured to connect to a CouchDB instance (or BigCouch or an http proxy for either). This configuration file can be found at:` $KAZOO/lib/whistle_couch-X.Y.Z/priv/startup.config`. The default config file should look like:
28 |
29 | `{default_couch_host,"localhost",5984,"username","password"}.`
30 |
31 | You may also have an entry similar to the above, but with `{couch_host...}` starting the config line. This is the line added by our **CouchDB** layer when successfully connecting to a **CouchDB** server. If you do not use authentication (Admin party!), leave username and password as empty strings (""). Alternatively, you can set the properties (except port) via the `whistle_apps_ctl` script mentioned above:
32 |
33 | `set_couch_host`: takes one parameter, the hostname to connect to.
34 |
35 | You will be prompted for the username and password. If you haven't set one, press for both questions. Your **WhApps** container should now be reading and writing to the new host.
36 |
37 |
38 | ## RabbitMQ
39 |
40 | Similar to **CouchDB**, we have an abstraction layer for **RabbitMQ** and a simple configuration file for it as well, located at:
41 |
42 | `$ KAZOO/lib/whistle_amqp-X.Y.Z/priv/startup.config`
43 |
44 | It defaults to: `{default_host, "localhost"}`.
45 |
46 | Alternatively, you can set the host via the `whistle_apps_ctl` script:
47 |
48 | `set_amqp_host`: takes one parameter, the host of a **RabbitMQ** broker.
49 |
--------------------------------------------------------------------------------
/doc/whapp/jonny5.md:
--------------------------------------------------------------------------------
1 | ## Jonny5 Account Limits
2 |
3 |
4 |
5 | `twoway_trunks`: 0, two way flat rate trunks can only be used if `system_config.jonny5.` `flat_rate_whitelist` `regex` matches AND `system_config.jonny5.` `flat_rate_blacklist` does not. This can also be specified as a `pvt_twoway_trunks`, the lower will be used.
6 |
7 | `inbound_trunks`: 0, exactly the same as two-way trunks but only used for inbound calls. If there are more inbound calls then trunks two-way trunks will be checked next.
8 |
9 | `resource_consuming_calls` : -1, hard limit on the number of calls that can consume one or more resources (IE: inbound to outbound forwarded number is one resource consuming call), can also be specified as `pvt_resource_consuming_calls`, the smallest of the two is used.
10 |
11 | `calls` : -1, total number of calls (resource consuming OR NOT) that an account can have, can also be specified as `pvt_calls`, the smallest of the two is used.
12 |
13 | `allow_prepay` : true, allows the customer to disable per_minute authorizations relying solely on trunks and/or allotments, this will be overridden by `pvt_allow prepay`.
14 |
15 | `pvt_type`: "limits",
16 |
17 | `pvt_vsn`: "1",
18 |
19 | `pvt_account_id`: "d75312345678901234567890",
20 |
21 | `pvt_account_db`: "account%2Fd7%2F53%12345678901234567890",
22 |
23 | `pvt_created`: 63518278682,
24 |
25 | `pvt_modified`: 63518278682,
26 |
27 | `pvt_soft_limit_outbound`: false, allows otherwise unauthorized outbound calls to continue
28 |
29 | `pvt_soft_limit_inbound`: true, allows otherwise unauthorized inbound calls to conitnue
30 |
31 | `pvt_allow_prepay`: true,
32 |
33 | `pvt_allow_postpay`: true, whether or not to allow the account to go negative
34 |
35 | `pvt_max_postpay_amount`: 100, the maximum negative amount that is acceptable
36 |
37 | `pvt_allotments`:
38 |
39 | `did_us`: then classification of a number as per system_config.number_manager.classifiers
40 |
41 | `amount`: 120, the allotment in seconds
42 |
43 | `cycle`: "hourly" the allotment reset period: yearly, monthly, weekly, daily, hourly, minutely
44 |
45 | `pvt_discounts`:
46 |
47 | `did_us`: then classification of a number as per system_config.number_manager.classifiers
48 |
49 | `percentage`: 10 - a percentage discount off the rate of EVERY per_minute call
50 |
51 | `pvt_enabled`: true, should limits be enforced for this account, IF FALSE THE ACCOUNT IS UNRESTRICTED
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/doc/whapp/stepswitch.md:
--------------------------------------------------------------------------------
1 | ## SUP Commands
2 |
3 |
4 |
5 | `sup stepswitch_maintenance flush`
6 |
7 | **Stepswitch** caches the properties of a number when it looks them up, including the account it belongs to. If the number is updated via the API it will be removed from the cache automatically. However, if a manual change is made you may want to flush the cache so it takes affect.
8 | ```
9 | shell
10 | [root@apps001 example]# /opt/kazoo/utils/sup/sup stepswitch_maintenance flush
11 | sup stepswitch_maintenance refresh
12 | ```
13 |
14 | **Stepswitch** uses the offnet database which must be set up properly so resources can be queried (see CouchDB views).
15 | This command will ensure the database is present, properly configured to the version of **Stepswitch** and clean up any depreciated documents that might be present.
16 | ```
17 | shell
18 | [root@apps001 example]# /opt/kazoo/utils/sup/sup stepswitch_maintenance refresh
19 | sup stepswitch_maintenance reload_resources
20 | ```
21 |
22 | **Stepswitch** monitors the offnet database for any changes (manual or API) and update the in-memory resource list.
23 | However, for older versions without this feature this command must be manually run on all servers with **Stepswitch** before new or updated resources are used.
24 | ```
25 | shell
26 | [root@apps001 example]# /opt/kazoo/utils/sup/sup stepswitch_maintenance reload_resources
27 | sup stepswitch_maintenance lookup_number {NUMBER}
28 | ```
29 |
30 | When provided with a number **Stepswitch** will return the known parameters of that number.
31 | These are drawn from the local cache if present or looked up and cached if not.
32 | This provides insight into what account a number is associated with for inbound calls as well as if outbound calls to this number will stay on-net.
33 |
34 | ```
35 | shell
36 | [root@apps001 example]# /opt/kazoo/utils/sup/sup stepswitch_maintenance lookup_number 4158867900
37 | {ok,
38 | 43579fc0a3aa11e29e960800200c9a66
39 | ,[{force_outbound,false},{pending_port,false},{local,false},{inbound_cnam,false}]}
40 | ```
41 |
42 | The return is formated as: `{ok, ACCOUNT ID, LIST OF PARAMETERS}`
43 |
44 | ## Parameters:
45 |
46 | `force_outbound` - If this is false when an account in the system calls this number it will no leave the **Kazoo** platform (known as on-net calls)
47 |
48 | `pending_port` - If this is true then the number was created as a port request but no inbound request from the carrier has not occurred yet (port is not complete).
49 |
50 | `inbound_cnam` - If this is true when inbound calls are made to this number a CNAM lookup will take place to update the caller id name in the US.
51 |
52 | ```shell
53 | sup stepswitch_maintenance reload_resources NUMBER
54 | ```
55 |
56 | This will return a ordered list of resource that would be attempted if the provided number was dialed.
57 |
58 | ```shell
59 | [root@apps001-aa-ord example]# /opt/kazoo/utils/sup/sup stepswitch_maintenance process_number 4158867998
60 | [{
61 | bae2f840a3d311e29e960800200c9a66
62 | ,0,
63 | sip:+14158867998@192.168.4.15
64 | },{
65 | bae2f840a3d311e29e960800200c9a66
66 | ,2,
67 | sip:+14158867998@192.168.4.16
68 | }]
69 | ```
70 |
71 | The return is formatted as a list of: `{RESOURCE ID, DELAY (in seconds), SIP URI}`
72 |
--------------------------------------------------------------------------------
/doc/whitelabeling/voicemail_to_email.md:
--------------------------------------------------------------------------------
1 | ## Voicemail to Email
2 |
3 |
4 |
5 | You can fetch the macros available for customization:
6 |
7 | ```shell
8 | curl -H "X-Auth-Token: $AUTH_TOKEN" http://crossbar:8000/v2/accounts/{ACCOUNT_ID}/notifications/voicemail_to_email | python -mjson.tool
9 | ```
10 |
11 | ```json
12 | "data": {...
13 | "macros": {
14 | "call_id": {
15 | "description": "Call ID of the caller",
16 | "friendly_name": "Call ID",
17 | "i18n_label": "call_id"
18 | },
19 | "callee_id.name": {
20 | "description": "Name of the callee",
21 | "friendly_name": "Callee ID Name",
22 | "i18n_label": "callee_id_name"
23 | },
24 | "callee_id.number": {
25 | "description": "Number of the callee",
26 | "friendly_name": "Callee ID Number",
27 | "i18n_label": "callee_id_number"
28 | },
29 | "caller_id.name": {
30 | "description": "Name of the caller",
31 | "friendly_name": "Caller ID Name",
32 | "i18n_label": "caller_id_name"
33 | },
34 | "caller_id.number": {
35 | "description": "Number of the caller",
36 | "friendly_name": "Caller ID Number",
37 | "i18n_label": "caller_id_number"
38 | },
39 | "date_called.local": {
40 | "description": "When was the voicemail left (Local time)",
41 | "friendly_name": "Date",
42 | "i18n_label": "date_called_local"
43 | },
44 | "date_called.utc": {
45 | "description": "When was the voicemail left (UTC)",
46 | "friendly_name": "Date (UTC)",
47 | "i18n_label": "date_called_utc"
48 | },
49 | "from.realm": {
50 | "description": "SIP From Realm",
51 | "friendly_name": "From Realm",
52 | "i18n_label": "from_realm"
53 | },
54 | "from.user": {
55 | "description": "SIP From Username",
56 | "friendly_name": "From User",
57 | "i18n_label": "from_user"
58 | },
59 | "owner.first_name": {
60 | "description": "First name of the owner of the voicemail box",
61 | "friendly_name": "First Name",
62 | "i18n_label": "first_name"
63 | },
64 | "owner.last_name": {
65 | "description": "Last name of the owner of the voicemail box",
66 | "friendly_name": "Last Name",
67 | "i18n_label": "last_name"
68 | },
69 | "to.realm": {
70 | "description": "SIP To Realm",
71 | "friendly_name": "To Realm",
72 | "i18n_label": "to_realm"
73 | },
74 | "to.user": {
75 | "description": "SIP To Username",
76 | "friendly_name": "To User",
77 | "i18n_label": "to_user"
78 | },
79 | "voicemail.box": {
80 | "description": "Which voicemail box was the message left in",
81 | "friendly_name": "Voicemail Box",
82 | "i18n_label": "voicemail_box"
83 | },
84 | "voicemail.length": {
85 | "description": "Length of the voicemail file",
86 | "friendly_name": "Voicemail Length",
87 | "i18n_label": "voicemail_length"
88 | },
89 | "voicemail.name": {
90 | "description": "Name of the voicemail file",
91 | "friendly_name": "Voicemail Name",
92 | "i18n_label": "voicemail_name"
93 | }
94 | }
95 | ,...
96 | }
97 | ```
98 |
99 | You can read more [here](https://github.com/2600hz/kazoo/blob/master/applications/crossbar/doc/notifications.md).
100 |
--------------------------------------------------------------------------------
/fix_docs.bash:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | function comment {
4 | echo comment out $1
5 | sed -i "\|$1| s|^|# |" doc/mkdocs/mkdocs.yml
6 | }
7 |
8 | for file in `find doc/ -size -1024c`; do
9 | comment $file
10 | done
11 |
--------------------------------------------------------------------------------
/make/splchk.mk:
--------------------------------------------------------------------------------
1 | .PHONY = splchk splchk-changed splchk-json splchk-code
2 |
3 | KAZOO_DICT = .aspell.en.pws
4 | KAZOO_REPL = .aspell.en.prepl
5 |
6 | $(ROOT)/$(KAZOO_DICT):
7 | @$(file >$(ROOT)/$(KAZOO_DICT),personal_ws-1.1 en 0 utf-8)
8 |
9 | $(ROOT)/$(KAZOO_REPL):
10 | @$(file >$(ROOT)/$(KAZOO_REPL),personal_repl-1.1 en 0 utf-8)
11 |
12 | splchk-init: $(ROOT)/$(KAZOO_DICT) $(ROOT)/$(KAZOO_REPL)
13 |
14 | ifeq ($(wildcard $(CURDIR)/doc/*.md),)
15 | splchk: splchk-init
16 | else
17 | DOCS := $(shell find $(CURDIR)/doc -type f -not -path "doc/mkdocs/*" -name "*.md")
18 | splchk: splchk-init $(addsuffix .chk,$(basename $(DOCS)))
19 | endif
20 |
21 | JSON := $(wildcard $(CURDIR)/priv/couchdb/schemas/*.json)
22 | ifeq ($(JSON),)
23 | splchk-json: splchk-init
24 | else
25 | splchk-json: splchk-init $(addsuffix .chk,$(basename $(JSON)))
26 | endif
27 |
28 | ESCRIPTS := $(wildcard $(CURDIR)/scripts/*.escript)
29 | SRC := $(wildcard $(CURDIR)/src/*.*rl) $(wildcard $(CURDIR)/src/*/*.erl) $(wildcard $(CURDIR)/include/*.hrl)
30 | CODE := $(SRC) $(ESCRIPTS)
31 | ifeq ($(CODE),)
32 | splchk-code: splchk-init
33 | else
34 | splchk-code: splchk-init $(addsuffix .chk,$(basename $(CODE)))
35 | endif
36 |
37 | splchk-changed: splchk-init $(addsuffix .chk,$(basename $(CHANGED)))
38 |
39 | %.chk: %.md
40 | @aspell --home-dir=$(ROOT) --personal=$(KAZOO_DICT) --repl=$(KAZOO_REPL) --lang=en -x check $<
41 |
42 | %.chk: %.json
43 | @aspell --home-dir=$(ROOT) --personal=$(KAZOO_DICT) --repl=$(KAZOO_REPL) --lang=en -x check $<
44 |
45 | %.chk: %.erl
46 | @aspell --add-filter-path=$(ROOT) --mode=erlang --home-dir=$(ROOT) --personal=$(KAZOO_DICT) --repl=$(KAZOO_REPL) --lang=en -x check $<
47 |
48 | %.chk: %.escript
49 | @aspell --add-filter-path=$(ROOT) --mode=erlang --home-dir=$(ROOT) --personal=$(KAZOO_DICT) --repl=$(KAZOO_REPL) --lang=en -x check $<
50 |
51 | %.chk: %.hrl
52 | @aspell --add-filter-path=$(ROOT) --mode=erlang --home-dir=$(ROOT) --personal=$(KAZOO_DICT) --repl=$(KAZOO_REPL) --lang=en -x check $<
53 |
--------------------------------------------------------------------------------
/scripts/reconcile_docs_to_index.bash:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | pushd $(dirname $0) > /dev/null
4 |
5 | cd $(pwd -P)/..
6 |
7 | doc_count=0
8 | missing_count=0
9 |
10 | function check_index {
11 | line=$(grep "$1" ./doc/mkdocs/mkdocs.yml | grep -v "#")
12 |
13 | if [ -f "$1" ] && [ -z "$line" ]; then
14 | [[ 0 -eq $missing_count ]] && echo "Docs missing from the mkdocs.yml index:"
15 | ((missing_count+=1))
16 | echo "$missing_count: '$1'"
17 | fi
18 | }
19 |
20 | docs=$(find {scripts,doc} \( -path 'doc/mkdocs' -o -path 'applications/*/doc/ref' \) -prune -o -type f -regex ".+\.md$")
21 | for doc in $docs; do
22 | ((doc_count+=1))
23 | check_index $doc
24 | done
25 |
26 | # if [[ $missing ]]; then
27 | ratio=$((100 * $missing_count / $doc_count))
28 | echo "Missing $missing_count / $doc_count: $ratio%"
29 | # fi
30 |
31 | popd > /dev/null
32 |
--------------------------------------------------------------------------------
/scripts/setup_docs.bash:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | ## sets up the docs environment to serve mkdocs-built site
3 |
4 | pushd $(dirname $0) > /dev/null
5 |
6 | cd $(pwd -P)/..
7 | DOCS_ROOT=./doc/mkdocs/docs
8 |
9 | find doc/ -type f -path "doc/mkdocs*" -prune -o -regex ".+\.\(md\|png\|jpg\|svg\)$" -print | cpio -p -dum --quiet $DOCS_ROOT
10 |
11 | cp $DOCS_ROOT/../index.md $DOCS_ROOT
12 |
13 | popd > /dev/null
14 |
--------------------------------------------------------------------------------
/scripts/validate_mkdocs.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import yaml, os.path, sys
4 | from functools import reduce
5 |
6 | # from https://stackoverflow.com/questions/5574702/how-to-print-to-stderr-in-python
7 | def eprint(*args, **kwargs):
8 | print(*args, file=sys.stderr, **kwargs)
9 |
10 | def parse_page_dict(errors_detected, kv):
11 | (header, pages) = kv
12 | if pages is None:
13 | eprint("section ", header, " is incomplete")
14 | return True
15 | else:
16 | return parse_page(errors_detected, pages)
17 |
18 | def parse_page_string(errors_detected, page):
19 | if "index.md" != page and (not os.path.isfile(page)):
20 | eprint("page ", page, " is not valid")
21 | return True
22 | else:
23 | return errors_detected
24 |
25 | def parse_page(errors_detected, page):
26 | "parse a page for existence"
27 | if isinstance(page, dict):
28 | return reduce(parse_page_dict, list(page.items()), errors_detected)
29 | elif isinstance(page, list):
30 | return reduce(parse_page, page, errors_detected)
31 | elif isinstance(page, str):
32 | return parse_page_string(errors_detected, page)
33 | else:
34 | return errors_detected
35 |
36 | stream = open("doc/mkdocs/mkdocs.yml", 'r')
37 | mkdocs = yaml.safe_load_all(stream)
38 | errors_detected = False
39 |
40 | for doc in mkdocs:
41 | for k,v in list(doc.items()):
42 | if "pages" == k:
43 | errors_detected = parse_page(False, v)
44 |
45 | if errors_detected:
46 | sys.exit(1)
47 |
--------------------------------------------------------------------------------
/wiki/Confluence-space-export-153629.html.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Confluence-space-export-153629.html.zip
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/13926531/14155782.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/13926531/14155782.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/13926531/14155784.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/13926531/14155784.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/13926531/14155786.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/13926531/14155786.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/17269210/17694735.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/17269210/17694735.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/22020107/22216705.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/22020107/22216705.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/4194375/17694722.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/4194375/17694722.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/4194375/17694724.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/4194375/17694724.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/4194509/43515905.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/4194509/43515905.jpg
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/4194509/43515906.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/4194509/43515906.jpg
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/4194509/43515907.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/4194509/43515907.jpg
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/4194509/43515908.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/4194509/43515908.jpg
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/4194509/43515909.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/4194509/43515909.jpg
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/4194509/43515910.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/4194509/43515910.jpg
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/4194509/43515911.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/4194509/43515911.jpg
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/4194509/43515912.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/4194509/43515912.jpg
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/4194509/43515913.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/4194509/43515913.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/4194509/43515914.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/4194509/43515914.jpg
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/6488074/6520834.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/6488074/6520834.jpg
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/6979633/151650308.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/6979633/151650308.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/6979633/30015572.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/6979633/30015572.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/6979633/66453507.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/6979633/66453507.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/6979633/66453509.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/6979633/66453509.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/6979633/66453511.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/6979633/66453511.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/6979633/7208963.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/6979633/7208963.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/6979633/7208965.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/6979633/7208965.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/6979633/7208967.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/6979633/7208967.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/6979633/7208969.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/6979633/7208969.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/6979633/7634946.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/6979633/7634946.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/7504053/7634948.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/7504053/7634948.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/7504053/7634950.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/7504053/7634950.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/7504155/7634951.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/7504155/7634951.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/7504155/7634952.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/7504155/7634952.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/7504155/7634953.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/7504155/7634953.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/7504155/7634954.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/7504155/7634954.png
--------------------------------------------------------------------------------
/wiki/Dedicated/attachments/7504155/7634955.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/attachments/7504155/7634955.png
--------------------------------------------------------------------------------
/wiki/Dedicated/images/icons/bullet_blue.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/images/icons/bullet_blue.gif
--------------------------------------------------------------------------------
/wiki/Dedicated/images/icons/contenttypes/home_page_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/images/icons/contenttypes/home_page_16.png
--------------------------------------------------------------------------------
/wiki/Dedicated/images/icons/grey_arrow_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/2600hz/docs-sysadmin/17fc48b5316f5f88b8bb97d1506d126e78b7b7c3/wiki/Dedicated/images/icons/grey_arrow_down.png
--------------------------------------------------------------------------------
/wiki/Dedicated/service-plans/intro.md:
--------------------------------------------------------------------------------
1 | ######**Service Plans**
2 |
3 | Service plans allow you to define pricing packages based on features utilized by a customer or reseller.
4 |
5 |
6 | ######**Service Limits**
7 |
8 | Service limits enforce real-time limits and quotas for individual accounts. Allow flat-rate calling to select areas or limit international calling.
9 |
10 |
11 | ######**Call Rating**
12 |
13 | Load a basic rate-deck into the system to allow for international calling and per-minute services, real-time. Compare your retail costs with actual costs.
14 |
--------------------------------------------------------------------------------
/wiki/parse_wiki.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python2
2 | ## Usage:
3 | ## for file in `find . -name *.html`; do ./parse_wiki.py $file; done
4 |
5 | import sys, os, re
6 | from HTMLParser import HTMLParser
7 |
8 | class WikiParser(HTMLParser):
9 | def __init__(self):
10 | HTMLParser.__init__(self)
11 | self.recording = 0
12 | self.data = []
13 |
14 | def handle_starttag(self, tag, attributes):
15 | if tag != 'div':
16 | return
17 | if self.recording:
18 | self.recording += 1
19 | return
20 | for name, value in attributes:
21 | if name == 'id' and value == 'main-content':
22 | break
23 | else:
24 | return
25 | self.recording = 1
26 |
27 | def handle_endtag(self, tag):
28 | if tag == 'div' and self.recording:
29 | self.recording -= 1
30 |
31 | def handle_data(self, data):
32 | if self.recording:
33 | self.data.append(data)
34 |
35 | html = open(sys.argv[1], 'r')
36 | wp = WikiParser()
37 |
38 | wp.feed(html.read())
39 | md = open(os.path.splitext(sys.argv[1])[0] + ".md", 'w')
40 |
41 | for line in wp.data:
42 | if not re.match('^\s+$', line):
43 | md.write("%s\n" % line)
44 |
45 | wp.close()
46 | md.close()
47 | html.close()
48 |
49 | os.remove(sys.argv[1])
50 |
--------------------------------------------------------------------------------