Пример #1
0
static Rlist *GetSQLTables(CfdbConn *cfdb)
{
    Rlist *list = NULL;
    char query[CF_MAXVARSIZE];

    ListTables(cfdb->type, query);

    CfNewQueryDB(cfdb, query);

    if (cfdb->maxcolumns != 1)
    {
        CfOut(cf_error, "", "Could not make sense of the columns");
        CfDeleteQuery(cfdb);
        return NULL;
    }

    while (CfFetchRow(cfdb))
    {
        PrependRScalar(&list, CfFetchColumn(cfdb, 0), CF_SCALAR);
    }

    CfDeleteQuery(cfdb);

    return list;
}
Пример #2
0
static Rlist *GetSQLTables(CfdbConn *cfdb)
{
    Rlist *list = NULL;
    char query[CF_MAXVARSIZE];

    ListTables(cfdb->type, query);

    CfNewQueryDB(cfdb, query);

    if (cfdb->maxcolumns != 1)
    {
        Log(LOG_LEVEL_ERR, "Could not make sense of the columns");
        CfDeleteQuery(cfdb);
        return NULL;
    }

    while (CfFetchRow(cfdb))
    {
        RlistPrepend(&list, CfFetchColumn(cfdb, 0), RVAL_TYPE_SCALAR);
    }

    CfDeleteQuery(cfdb);

    return list;
}
Пример #3
0
void CfVoidQueryDB(CfdbConn *cfdb, char *query)
{
    if (!cfdb->connected)
    {
        return;
    }

/* If we don't need to retrieve table entries...*/
    CfNewQueryDB(cfdb, query);
    CfDeleteQuery(cfdb);
}
Пример #4
0
static int VerifyTablePromise(CfdbConn *cfdb, char *table_path, Rlist *columns, Attributes a, Promise *pp)
{
    char name[CF_MAXVARSIZE], type[CF_MAXVARSIZE], query[CF_MAXVARSIZE], table[CF_MAXVARSIZE], db[CF_MAXVARSIZE];
    int i, count, size, no_of_cols, *size_table, *done, identified, retval = true;
    char **name_table, **type_table;

    CfOut(cf_verbose, "", " -> Verifying promised table structure for \"%s\"", table_path);

    if (!ValidateSQLTableName(table_path, db, table))
    {
        CfOut(cf_error, "",
              " !! The structure of the promiser did not match that for an SQL table, i.e. \"database.table\"\n");
        return false;
    }
    else
    {
        CfOut(cf_verbose, "", " -> Assuming database \"%s\" with table \"%s\"", db, table);
    }

/* Verify the existence of the tables within the database */

    if (!TableExists(cfdb, table))
    {
        CfOut(cf_error, "", " !! The database did not contain the promised table \"%s\"\n", table_path);

        if ((a.database.operation) && (strcmp(a.database.operation, "create") == 0))
        {
            if ((!DONTDO) && ((a.transaction.action) != cfa_warn))
            {
                cfPS(cf_error, CF_CHG, "", pp, a, " -> Database.table %s doesn't seem to exist, creating\n",
                     table_path);
                return CreateTableColumns(cfdb, table, columns, a, pp);
            }
            else
            {
                CfOut(cf_error, "", " -> Database.table %s doesn't seem to exist, but only a warning was promised\n",
                      table_path);
            }
        }

        return false;
    }

/* Get a list of the columns in the table */

    QueryTableColumns(query, db, table);
    CfNewQueryDB(cfdb, query);

    if (cfdb->maxcolumns != 3)
    {
        cfPS(cf_error, CF_FAIL, "", pp, a, "Could not make sense of the columns");
        CfDeleteQuery(cfdb);
        return false;
    }

/* Assume that the Rlist has been validated and consists of a,b,c */

    count = 0;
    no_of_cols = RlistLen(columns);

    if (!NewSQLColumns(table, columns, &name_table, &type_table, &size_table, &done))
    {
        cfPS(cf_error, CF_FAIL, "", pp, a, "Could not make sense of the columns");
        return false;
    }

/* Obtain columns from the named table - if any */

    while (CfFetchRow(cfdb))
    {
        char *sizestr;

        name[0] = '\0';
        type[0] = '\0';
        size = CF_NOINT;

        strlcpy(name, CfFetchColumn(cfdb, 0), CF_MAXVARSIZE);
        strlcpy(type, CfFetchColumn(cfdb, 1), CF_MAXVARSIZE);
        ToLowerStrInplace(type);
        sizestr = CfFetchColumn(cfdb, 2);

        if (sizestr)
        {
            size = Str2Int(sizestr);
        }

        CfOut(cf_verbose, "", "    ... discovered column (%s,%s,%d)", name, type, size);

        if (sizestr && (size == CF_NOINT))
        {
            cfPS(cf_verbose, CF_NOP, "", pp, a,
                 " !! Integer size of SQL datatype could not be determined or was not specified - invalid promise.");
            DeleteSQLColumns(name_table, type_table, size_table, done, no_of_cols);
            CfDeleteQuery(cfdb);
            return false;
        }

        identified = false;

        for (i = 0; i < no_of_cols; i++)
        {
            if (done[i])
            {
                continue;
            }

            if (strcmp(name, name_table[i]) == 0)
            {
                CheckSQLDataType(type, type_table[i], pp);

                if (size != size_table[i])
                {
                    cfPS(cf_error, CF_FAIL, "", pp, a,
                         " !! Promised column \"%s\" in database.table \"%s\" has a non-matching array size (%d != %d)",
                         name, table_path, size, size_table[i]);
                }
                else
                {
                    CfOut(cf_verbose, "", " -> Promised column \"%s\" in database.table \"%s\" is as promised", name,
                          table_path);
                }

                count++;
                done[i] = true;
                identified = true;
                break;
            }
        }

        if (!identified)
        {
            cfPS(cf_error, CF_FAIL, "", pp, a,
                 "Column \"%s\" found in database.table \"%s\" is not part of its promise.", name, table_path);

            if ((a.database.operation) && (strcmp(a.database.operation, "drop") == 0))
            {
                cfPS(cf_error, CF_FAIL, "", pp, a,
                     "Cfengine will not promise to repair this, as the operation is potentially too destructive.");
                // Future allow deletion?
            }

            retval = false;
        }
    }

    CfDeleteQuery(cfdb);

/* Now look for deviations - only if we have promised to create missing */

    if ((a.database.operation) && (strcmp(a.database.operation, "drop") == 0))
    {
        return retval;
    }

    if (count != no_of_cols)
    {
        for (i = 0; i < no_of_cols; i++)
        {
            if (!done[i])
            {
                CfOut(cf_error, "", " !! Promised column \"%s\" missing from database table %s", name_table[i],
                      pp->promiser);

                if ((!DONTDO) && ((a.transaction.action) != cfa_warn))
                {
                    if (size_table[i] > 0)
                    {
                        snprintf(query, CF_MAXVARSIZE - 1, "ALTER TABLE %s ADD %s %s(%d)", table, name_table[i],
                                 type_table[i], size_table[i]);
                    }
                    else
                    {
                        snprintf(query, CF_MAXVARSIZE - 1, "ALTER TABLE %s ADD %s %s", table, name_table[i],
                                 type_table[i]);
                    }

                    CfVoidQueryDB(cfdb, query);
                    cfPS(cf_error, CF_CHG, "", pp, a, " !! Adding promised column \"%s\" to database table %s",
                         name_table[i], table);
                    retval = true;
                }
                else
                {
                    cfPS(cf_error, CF_WARN, "", pp, a,
                         " !! Promised column \"%s\" missing from database table %s but only a warning was promised",
                         name_table[i], table);
                    retval = false;
                }
            }
        }
    }

    DeleteSQLColumns(name_table, type_table, size_table, done, no_of_cols);

    return retval;
}
Пример #5
0
static int VerifyTablePromise(EvalContext *ctx, CfdbConn *cfdb, char *table_path, Rlist *columns, const Attributes *a,
                              const Promise *pp, PromiseResult *result)
{
    assert(a != NULL);
    char name[CF_MAXVARSIZE], type[CF_MAXVARSIZE], query[CF_MAXVARSIZE], table[CF_MAXVARSIZE], db[CF_MAXVARSIZE];
    int i, count, size, no_of_cols, *size_table, *done, identified, retval = true;
    char **name_table, **type_table;

    Log(LOG_LEVEL_VERBOSE, "Verifying promised table structure for '%s'", table_path);

    if (!ValidateSQLTableName(table_path, db, table))
    {
        Log(LOG_LEVEL_ERR,
            "The structure of the promiser did not match that for an SQL table, i.e. 'database.table'");
        return false;
    }
    else
    {
        Log(LOG_LEVEL_VERBOSE, "Assuming database '%s' with table '%s'", db, table);
    }

/* Verify the existence of the tables within the database */

    if (!TableExists(cfdb, table))
    {
        Log(LOG_LEVEL_ERR, "The database did not contain the promised table '%s'", table_path);

        if ((a->database.operation) && (strcmp(a->database.operation, "create") == 0))
        {
            if ((!DONTDO) && ((a->transaction.action) != cfa_warn))
            {
                cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_CHANGE, pp, a, "Database.table '%s' doesn't seem to exist, creating",
                     table_path);
                *result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE);
                return CreateTableColumns(cfdb, table, columns);
            }
            else
            {
                Log(LOG_LEVEL_WARNING, "Database.table '%s' doesn't seem to exist, but only a warning was promised",
                      table_path);
            }
        }

        return false;
    }

/* Get a list of the columns in the table */

    QueryTableColumns(query, db, table);
    CfNewQueryDB(cfdb, query);

    if (cfdb->maxcolumns != 3)
    {
        cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Could not make sense of the columns");
        *result = PromiseResultUpdate(*result, PROMISE_RESULT_FAIL);
        CfDeleteQuery(cfdb);
        return false;
    }

/* Assume that the Rlist has been validated and consists of a,b,c */

    count = 0;
    no_of_cols = RlistLen(columns);

    if (!NewSQLColumns(table, columns, &name_table, &type_table, &size_table, &done))
    {
        cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Could not make sense of the columns");
        *result = PromiseResultUpdate(*result, PROMISE_RESULT_FAIL);
        return false;
    }

/* Obtain columns from the named table - if any */

    while (CfFetchRow(cfdb))
    {
        char *sizestr;

        name[0] = '\0';
        type[0] = '\0';
        size = CF_NOINT;

        strlcpy(name, CfFetchColumn(cfdb, 0), CF_MAXVARSIZE);
        strlcpy(type, CfFetchColumn(cfdb, 1), CF_MAXVARSIZE);
        ToLowerStrInplace(type);
        sizestr = CfFetchColumn(cfdb, 2);

        if (sizestr)
        {
            size = IntFromString(sizestr);
        }

        Log(LOG_LEVEL_VERBOSE, "Discovered database column (%s,%s,%d)", name, type, size);

        if (sizestr && (size == CF_NOINT))
        {
            cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a,
                 "Integer size of SQL datatype could not be determined or was not specified - invalid promise.");
            DeleteSQLColumns(name_table, type_table, size_table, done, no_of_cols);
            CfDeleteQuery(cfdb);
            return false;
        }

        identified = false;

        for (i = 0; i < no_of_cols; i++)
        {
            if (done[i])
            {
                continue;
            }

            if (strcmp(name, name_table[i]) == 0)
            {
                CheckSQLDataType(type, type_table[i], pp);

                if (size != size_table[i])
                {
                    cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a,
                         "Promised column '%s' in database.table '%s' has a non-matching array size (%d != %d)",
                         name, table_path, size, size_table[i]);
                    *result = PromiseResultUpdate(*result, PROMISE_RESULT_FAIL);
                }
                else
                {
                    Log(LOG_LEVEL_VERBOSE, "Promised column '%s' in database.table '%s' is as promised", name,
                          table_path);
                }

                count++;
                done[i] = true;
                identified = true;
                break;
            }
        }

        if (!identified)
        {
            cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a,
                 "Column '%s' found in database.table '%s' is not part of its promise.", name, table_path);
            *result = PromiseResultUpdate(*result, PROMISE_RESULT_FAIL);

            if ((a->database.operation) && (strcmp(a->database.operation, "drop") == 0))
            {
                cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a,
                     "CFEngine will not promise to repair this, as the operation is potentially too destructive.");
                // Future allow deletion?
                *result = PromiseResultUpdate(*result, PROMISE_RESULT_FAIL);
            }

            retval = false;
        }
    }

    CfDeleteQuery(cfdb);

/* Now look for deviations - only if we have promised to create missing */

    if ((a->database.operation) && (strcmp(a->database.operation, "drop") == 0))
    {
        return retval;
    }

    if (count != no_of_cols)
    {
        for (i = 0; i < no_of_cols; i++)
        {
            if (!done[i])
            {
                Log(LOG_LEVEL_ERR, "Promised column '%s' missing from database table '%s'", name_table[i],
                      pp->promiser);

                if ((!DONTDO) && ((a->transaction.action) != cfa_warn))
                {
                    if (size_table[i] > 0)
                    {
                        snprintf(query, CF_MAXVARSIZE - 1, "ALTER TABLE %s ADD %s %s(%d)", table, name_table[i],
                                 type_table[i], size_table[i]);
                    }
                    else
                    {
                        snprintf(query, CF_MAXVARSIZE - 1, "ALTER TABLE %s ADD %s %s", table, name_table[i],
                                 type_table[i]);
                    }

                    CfVoidQueryDB(cfdb, query);
                    cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_CHANGE, pp, a, "Adding promised column '%s' to database table '%s'",
                         name_table[i], table);
                    *result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE);
                    retval = true;
                }
                else
                {
                    cfPS(ctx, LOG_LEVEL_WARNING, PROMISE_RESULT_WARN, pp, a,
                         "Promised column '%s' missing from database table '%s' but only a warning was promised",
                         name_table[i], table);
                    *result = PromiseResultUpdate(*result, PROMISE_RESULT_WARN);
                    retval = false;
                }
            }
        }
    }

    DeleteSQLColumns(name_table, type_table, size_table, done, no_of_cols);

    return retval;
}