github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/core/ledger/util/couchdb/couchdbutil.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package couchdb 18 19 import ( 20 "fmt" 21 "regexp" 22 "strconv" 23 "strings" 24 ) 25 26 var validNamePattern = `^[a-z][a-z0-9_$(),+/-]+` 27 var maxLength = 249 28 29 //CreateCouchInstance creates a CouchDB instance 30 func CreateCouchInstance(couchDBConnectURL string, id string, pw string) (*CouchInstance, error) { 31 couchConf, err := CreateConnectionDefinition(couchDBConnectURL, 32 id, 33 pw) 34 if err != nil { 35 logger.Errorf("Error during CouchDB CreateConnectionDefinition(): %s\n", err.Error()) 36 return nil, err 37 } 38 39 //Create the CouchDB instance 40 couchInstance := &CouchInstance{conf: *couchConf} 41 42 connectInfo, retVal, verifyErr := couchInstance.VerifyConnection() 43 if verifyErr != nil { 44 return nil, fmt.Errorf("Unable to connect to CouchDB, check the hostname and port: %s", verifyErr.Error()) 45 } 46 47 //return an error if the http return value is not 200 48 if retVal.StatusCode != 200 { 49 return nil, fmt.Errorf("CouchDB connection error, expecting return code of 200, received %v", retVal.StatusCode) 50 } 51 52 //check the CouchDB version number, return an error if the version is not at least 2.0.0 53 errVersion := checkCouchDBVersion(connectInfo.Version) 54 if errVersion != nil { 55 return nil, errVersion 56 } 57 58 return couchInstance, nil 59 } 60 61 //checkCouchDBVersion verifies CouchDB is at least 2.0.0 62 func checkCouchDBVersion(version string) error { 63 64 //split the version into parts 65 majorVersion := strings.Split(version, ".") 66 67 //check to see that the major version number is at least 2 68 majorVersionInt, _ := strconv.Atoi(majorVersion[0]) 69 if majorVersionInt < 2 { 70 return fmt.Errorf("CouchDB must be at least version 2.0.0. Detected version %s", version) 71 } 72 73 return nil 74 } 75 76 //CreateCouchDatabase creates a CouchDB database object, as well as the underlying database if it does not exist 77 func CreateCouchDatabase(couchInstance CouchInstance, dbName string) (*CouchDatabase, error) { 78 79 databaseName, err := mapAndValidateDatabaseName(dbName) 80 if err != nil { 81 logger.Errorf("Error during CouchDB CreateDatabaseIfNotExist() for dbName: %s error: %s\n", dbName, err.Error()) 82 return nil, err 83 } 84 85 couchDBDatabase := CouchDatabase{couchInstance: couchInstance, dbName: databaseName} 86 87 // Create CouchDB database upon ledger startup, if it doesn't already exist 88 _, err = couchDBDatabase.CreateDatabaseIfNotExist() 89 if err != nil { 90 logger.Errorf("Error during CouchDB CreateDatabaseIfNotExist() for dbName: %s error: %s\n", dbName, err.Error()) 91 return nil, err 92 } 93 94 return &couchDBDatabase, nil 95 } 96 97 //mapAndValidateDatabaseName checks to see if the database name contains illegal characters 98 //CouchDB Rules: Only lowercase characters (a-z), digits (0-9), and any of the characters 99 //_, $, (, ), +, -, and / are allowed. Must begin with a letter. 100 // 101 //Restictions have already been applied to the database name from Orderer based on 102 //restrictions required by Kafka 103 // 104 //The validation will validate upper case, the string will be lower cased 105 //Replace any characters not allowed in CouchDB with an "_" 106 //Check for a leading letter, if not present, the prepend "db_" 107 func mapAndValidateDatabaseName(databaseName string) (string, error) { 108 109 // test Length 110 if len(databaseName) <= 0 { 111 return "", fmt.Errorf("Database name is illegal, cannot be empty") 112 } 113 if len(databaseName) > maxLength { 114 return "", fmt.Errorf("Database name is illegal, cannot be longer than %d", maxLength) 115 } 116 117 //force the name to all lowercase 118 databaseName = strings.ToLower(databaseName) 119 120 //Replace any characters not allowed in CouchDB with an "_" 121 replaceString := regexp.MustCompile(`[^a-z0-9_$(),+/-]`) 122 123 //Set up the replace pattern for special characters 124 validatedDatabaseName := replaceString.ReplaceAllString(databaseName, "_") 125 126 //if the first character is not a letter, then prepend "db_" 127 testLeadingLetter := regexp.MustCompile("^[a-z]") 128 isLeadingLetter := testLeadingLetter.MatchString(validatedDatabaseName) 129 if !isLeadingLetter { 130 validatedDatabaseName = "db_" + validatedDatabaseName 131 } 132 133 //create the expression for valid characters 134 validString := regexp.MustCompile(validNamePattern) 135 136 // Illegal characters 137 matched := validString.MatchString(validatedDatabaseName) 138 if !matched { 139 return "", fmt.Errorf("Database name '%s' contains illegal characters", validatedDatabaseName) 140 } 141 return validatedDatabaseName, nil 142 }