| @ -0,0 +1,13 @@ | |||
| export IMG_VERSION = 7.5 | |||
| # limpia todo | |||
| all: imagen clean install | |||
| imagen: | |||
| cd ../servicios; make | |||
| install: | |||
| envsubst < repostajes-deployment.yaml |kubectl create -f - | |||
| clean: | |||
| envsubst < repostajes-deployment.yaml |kubectl delete -f - | |||
| @ -0,0 +1,14 @@ | |||
| apiVersion: v1 | |||
| kind: PersistentVolume | |||
| metadata: | |||
| name: repostajes-app-folder | |||
| labels: | |||
| app: repostajes | |||
| spec: | |||
| capacity: | |||
| storage: 100Mi | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| hostPath: | |||
| path: "/mnt/Externo/repostajes" | |||
| @ -0,0 +1,56 @@ | |||
| apiVersion: v1 | |||
| kind: Service | |||
| metadata: | |||
| name: repostajes | |||
| spec: | |||
| type: NodePort | |||
| ports: | |||
| - name: http | |||
| port: 5000 | |||
| nodePort: 30340 | |||
| targetPort: repostajes | |||
| selector: | |||
| app: repostajes | |||
| --- | |||
| apiVersion: apps/v1 | |||
| kind: Deployment | |||
| metadata: | |||
| name: repostajes | |||
| labels: | |||
| app: repostajes | |||
| spec: | |||
| replicas: 1 | |||
| selector: | |||
| matchLabels: | |||
| app: repostajes | |||
| strategy: | |||
| type: Recreate | |||
| template: | |||
| metadata: | |||
| labels: | |||
| app: repostajes | |||
| spec: | |||
| containers: | |||
| - args: | |||
| - gunicorn | |||
| - --bind | |||
| - 0.0.0.0:5000 | |||
| - repostajes:create_app() | |||
| image: creylopez/repostajes:$IMG_VERSION | |||
| name: repostajes | |||
| env: | |||
| - name: SALUDO_DEMO | |||
| value: "Hola, mundo" | |||
| ports: | |||
| - containerPort: 5000 | |||
| name: repostajes | |||
| resources: {} | |||
| volumeMounts: | |||
| - mountPath: /repostajes/instance | |||
| name: repostajes-prod | |||
| restartPolicy: Always | |||
| volumes: | |||
| - name: repostajes-prod | |||
| persistentVolumeClaim: | |||
| claimName: repostajes-prod | |||
| status: {} | |||
| @ -0,0 +1,14 @@ | |||
| apiVersion: v1 | |||
| kind: PersistentVolumeClaim | |||
| metadata: | |||
| creationTimestamp: null | |||
| labels: | |||
| io.kompose.service: repostajes-prod | |||
| name: repostajes-prod | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteOnce | |||
| resources: | |||
| requests: | |||
| storage: 100Mi | |||
| status: {} | |||
| @ -0,0 +1,44 @@ | |||
| # Arreglar el fallo del nombre de constrain en migraciones | |||
| https://stackoverflow.com/questions/62640576/flask-migrate-valueerror-constraint-must-have-a-name | |||
| # Uso de migraciones | |||
| https://www.digitalocean.com/community/tutorials/how-to-perform-flask-sqlalchemy-migrations-using-flask-migrate | |||
| # Migración de la base de datos. | |||
| Cada vez que se haga un cambio en la bd | |||
| - flask db migrate -m "Mensaje" | |||
| - flask db upgrade | |||
| ## Migration Workflow | |||
| From this point on you have a project that is fully enabled to use database migrations. The normal migration process goes as follows: | |||
| - You will make some changes to your models in your Python source code. | |||
| - You will then run flask db migrate to generate a new database migration for these changes. | |||
| - You will finally apply the changes to the database by running flask db upgrade. | |||
| This cycle repeats every time new changes to the database schema are needed. | |||
| # Insertar los datos en la base de datos desde fichero sql | |||
| 1. Borrar la base de datos. | |||
| 2. flask db init | |||
| 3. flask db migrate | |||
| 4. flask db upgrade | |||
| con lo anterior queda creada la base de datos. | |||
| 5. Insertar los ficheros SQL con: | |||
| sqlite3 repostajes.db < vehiculos.sql | |||
| sqlite3 repostajes.db < repostajes.sql | |||
| ¡ojo! estos ficheros son un volcado de mysql. Hay que 'tocarlos' para ajustarse al nuevo modelo. Los que hay aquí ya están adaptados | |||
| @ -0,0 +1,8 @@ | |||
| install: | |||
| echo "Creando imagen con version ${IMG_VERSION}" | |||
| docker build --no-cache -t creylopez/repostajes:${IMG_VERSION} . | |||
| docker push creylopez/repostajes:${IMG_VERSION} | |||
| @ -0,0 +1 @@ | |||
| Single-database configuration for Flask. | |||
| @ -0,0 +1,50 @@ | |||
| # A generic, single database configuration. | |||
| [alembic] | |||
| # template used to generate migration files | |||
| # file_template = %%(rev)s_%%(slug)s | |||
| # set to 'true' to run the environment during | |||
| # the 'revision' command, regardless of autogenerate | |||
| # revision_environment = false | |||
| # Logging configuration | |||
| [loggers] | |||
| keys = root,sqlalchemy,alembic,flask_migrate | |||
| [handlers] | |||
| keys = console | |||
| [formatters] | |||
| keys = generic | |||
| [logger_root] | |||
| level = WARN | |||
| handlers = console | |||
| qualname = | |||
| [logger_sqlalchemy] | |||
| level = WARN | |||
| handlers = | |||
| qualname = sqlalchemy.engine | |||
| [logger_alembic] | |||
| level = INFO | |||
| handlers = | |||
| qualname = alembic | |||
| [logger_flask_migrate] | |||
| level = INFO | |||
| handlers = | |||
| qualname = flask_migrate | |||
| [handler_console] | |||
| class = StreamHandler | |||
| args = (sys.stderr,) | |||
| level = NOTSET | |||
| formatter = generic | |||
| [formatter_generic] | |||
| format = %(levelname)-5.5s [%(name)s] %(message)s | |||
| datefmt = %H:%M:%S | |||
| @ -0,0 +1,113 @@ | |||
| import logging | |||
| from logging.config import fileConfig | |||
| from flask import current_app | |||
| from alembic import context | |||
| # this is the Alembic Config object, which provides | |||
| # access to the values within the .ini file in use. | |||
| config = context.config | |||
| # Interpret the config file for Python logging. | |||
| # This line sets up loggers basically. | |||
| fileConfig(config.config_file_name) | |||
| logger = logging.getLogger('alembic.env') | |||
| def get_engine(): | |||
| try: | |||
| # this works with Flask-SQLAlchemy<3 and Alchemical | |||
| return current_app.extensions['migrate'].db.get_engine() | |||
| except (TypeError, AttributeError): | |||
| # this works with Flask-SQLAlchemy>=3 | |||
| return current_app.extensions['migrate'].db.engine | |||
| def get_engine_url(): | |||
| try: | |||
| return get_engine().url.render_as_string(hide_password=False).replace( | |||
| '%', '%%') | |||
| except AttributeError: | |||
| return str(get_engine().url).replace('%', '%%') | |||
| # add your model's MetaData object here | |||
| # for 'autogenerate' support | |||
| # from myapp import mymodel | |||
| # target_metadata = mymodel.Base.metadata | |||
| config.set_main_option('sqlalchemy.url', get_engine_url()) | |||
| target_db = current_app.extensions['migrate'].db | |||
| # other values from the config, defined by the needs of env.py, | |||
| # can be acquired: | |||
| # my_important_option = config.get_main_option("my_important_option") | |||
| # ... etc. | |||
| def get_metadata(): | |||
| if hasattr(target_db, 'metadatas'): | |||
| return target_db.metadatas[None] | |||
| return target_db.metadata | |||
| def run_migrations_offline(): | |||
| """Run migrations in 'offline' mode. | |||
| This configures the context with just a URL | |||
| and not an Engine, though an Engine is acceptable | |||
| here as well. By skipping the Engine creation | |||
| we don't even need a DBAPI to be available. | |||
| Calls to context.execute() here emit the given string to the | |||
| script output. | |||
| """ | |||
| url = config.get_main_option("sqlalchemy.url") | |||
| context.configure( | |||
| url=url, target_metadata=get_metadata(), literal_binds=True | |||
| ) | |||
| with context.begin_transaction(): | |||
| context.run_migrations() | |||
| def run_migrations_online(): | |||
| """Run migrations in 'online' mode. | |||
| In this scenario we need to create an Engine | |||
| and associate a connection with the context. | |||
| """ | |||
| # this callback is used to prevent an auto-migration from being generated | |||
| # when there are no changes to the schema | |||
| # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html | |||
| def process_revision_directives(context, revision, directives): | |||
| if getattr(config.cmd_opts, 'autogenerate', False): | |||
| script = directives[0] | |||
| if script.upgrade_ops.is_empty(): | |||
| directives[:] = [] | |||
| logger.info('No changes in schema detected.') | |||
| conf_args = current_app.extensions['migrate'].configure_args | |||
| if conf_args.get("process_revision_directives") is None: | |||
| conf_args["process_revision_directives"] = process_revision_directives | |||
| connectable = get_engine() | |||
| with connectable.connect() as connection: | |||
| context.configure( | |||
| connection=connection, | |||
| target_metadata=get_metadata(), | |||
| **conf_args | |||
| ) | |||
| with context.begin_transaction(): | |||
| context.run_migrations() | |||
| if context.is_offline_mode(): | |||
| run_migrations_offline() | |||
| else: | |||
| run_migrations_online() | |||
| @ -0,0 +1,24 @@ | |||
| """${message} | |||
| Revision ID: ${up_revision} | |||
| Revises: ${down_revision | comma,n} | |||
| Create Date: ${create_date} | |||
| """ | |||
| from alembic import op | |||
| import sqlalchemy as sa | |||
| ${imports if imports else ""} | |||
| # revision identifiers, used by Alembic. | |||
| revision = ${repr(up_revision)} | |||
| down_revision = ${repr(down_revision)} | |||
| branch_labels = ${repr(branch_labels)} | |||
| depends_on = ${repr(depends_on)} | |||
| def upgrade(): | |||
| ${upgrades if upgrades else "pass"} | |||
| def downgrade(): | |||
| ${downgrades if downgrades else "pass"} | |||